• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dennisdoomen / reflectify / 31389059491

10 Aug 2026 12:39PM UTC coverage: 96.835%. Remained the same
31389059491

Pull #169

github

web-flow
Merge d97657d86 into 6dbba80ba
Pull Request #169: Split Reflectify.cs into one file per type

209 of 222 branches covered (94.14%)

Branch coverage included in aggregate %.

403 of 410 new or added lines in 8 files covered. (98.29%)

403 of 410 relevant lines covered (98.29%)

5365877.43 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

93.79
/src/Reflectify/TypeMetaDataExtensions.cs
1
#if !REFLECTIFY_COMPILE
2
// <autogenerated />
3
#pragma warning disable
4
#endif
5

6
#nullable disable
7

8
using System;
9
using System.Collections.Generic;
10
using System.Linq;
11
using System.Reflection;
12
using System.Runtime.CompilerServices;
13
using System.Text;
14

15
namespace Reflectify;
16

17
internal static class TypeMetaDataExtensions
18
{
19
    /// <summary>
20
    /// Returns the name of the type without the generic backtick and the type arguments.
21
    /// </summary>
22
    public static string GetNonGenericName(this Type type)
23
    {
8✔
24
        string name = type.Name;
8✔
25
        int index = name.IndexOf('`');
8✔
26
        return index == -1 ? name : name.Substring(0, index);
8✔
27
    }
8✔
28

29
    /// <summary>
30
    /// Returns <see langword="true" /> if the type is derived from an open-generic type, or <see langword="false" /> otherwise.
31
    /// </summary>
32
    public static bool IsDerivedFromOpenGeneric(this Type type, Type openGenericType)
33
    {
6✔
34
        // do not consider a type to be derived from itself
35
        if (type == openGenericType)
6✔
36
        {
2✔
37
            return false;
2✔
38
        }
39

40
        // check subject and its base types against definition
41
        for (Type baseType = type;
4✔
42
             baseType is not null;
10✔
43
             baseType = baseType.BaseType)
6✔
44
        {
8✔
45
            if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == openGenericType)
8✔
46
            {
2✔
47
                return true;
2✔
48
            }
49
        }
6✔
50

51
        return false;
2✔
52
    }
6✔
53

54
    /// <summary>
55
    /// Returns the interfaces that the <paramref name="type"/> implements or inherits from that are concrete
56
    /// versions of the <paramref name="openGenericType"/>.
57
    /// </summary>
58
    public static Type[] GetClosedGenericInterfaces(this Type type, Type openGenericType)
59
    {
8✔
60
        if (type.IsGenericType && type.GetGenericTypeDefinition() == openGenericType)
8!
NEW
61
        {
×
NEW
62
            return [type];
×
63
        }
64

65
        Type[] interfaces = type.GetInterfaces();
8✔
66

67
        return interfaces
8✔
68
            .Where(t => t.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == openGenericType))
10✔
69
            .ToArray();
8✔
70
    }
8✔
71

72
    /// <summary>
73
    /// Returns <see langword="true" /> if the type is decorated with the specific <typeparamref name="TAttribute"/>,
74
    /// or <see langword="false" /> otherwise.
75
    /// </summary>
76
    public static bool HasAttribute<TAttribute>(this Type type)
77
        where TAttribute : Attribute
78
    {
22✔
79
        return type.IsDefined(typeof(TAttribute), inherit: false);
22✔
80
    }
22✔
81

82
    /// <summary>
83
    /// Returns <see langword="true" /> if the type is decorated with the specific <typeparamref name="TAttribute"/> <i>and</i>
84
    /// that attribute instance matches the predicate, or <see langword="false" /> otherwise.
85
    /// </summary>
86
    public static bool HasAttribute<TAttribute>(this Type type, Func<TAttribute, bool> predicate)
87
        where TAttribute : Attribute
88
    {
10✔
89
        if (predicate is null)
10✔
90
        {
2✔
91
            throw new ArgumentNullException(nameof(predicate));
2✔
92
        }
93

94
        return type.GetCustomAttributes<TAttribute>(inherit: false).Any(predicate);
8✔
95
    }
8✔
96

97
    /// <summary>
98
    /// Returns <see langword="true" /> if the type or one its parents are decorated with the
99
    /// specific <typeparamref name="TAttribute"/>.
100
    /// </summary>
101
    public static bool HasAttributeInHierarchy<TAttribute>(this Type type)
102
        where TAttribute : Attribute
103
    {
6✔
104
        return type.IsDefined(typeof(TAttribute), inherit: true);
6✔
105
    }
6✔
106

107
    /// <summary>
108
    /// Returns <see langword="true" /> if the type or one its parents are decorated with the
109
    /// specific <typeparamref name="TAttribute"/> <i>and</i> that attribute instance
110
    /// matches the predicate. Returns <see langword="false" /> otherwise.
111
    /// </summary>
112
    public static bool HasAttributeInHierarchy<TAttribute>(this Type type, Func<TAttribute, bool> predicate)
113
        where TAttribute : Attribute
114
    {
8✔
115
        if (predicate is null)
8✔
116
        {
4✔
117
            throw new ArgumentNullException(nameof(predicate));
4✔
118
        }
119

120
        return type.GetCustomAttributes<TAttribute>(inherit: true).Any(predicate);
4✔
121
    }
4✔
122

123
    /// <summary>
124
    /// Retrieves all custom attributes of the specified type from a class or its inheritance hierarchy.
125
    /// </summary>
126
    public static TAttribute[] GetMatchingAttributes<TAttribute>(this Type type)
127
        where TAttribute : Attribute
128
    {
4✔
129
        return (TAttribute[])type.GetCustomAttributes<TAttribute>(inherit: true);
4✔
130
    }
4✔
131

132
    /// <summary>
133
    /// Retrieves an array of attributes of a specified type that match the provided predicate.
134
    /// </summary>
135
    public static TAttribute[] GetMatchingAttributes<TAttribute>(this Type type, Func<TAttribute, bool> predicate)
136
        where TAttribute : Attribute
137
    {
8✔
138
        if (predicate is null)
8!
NEW
139
        {
×
NEW
140
            throw new ArgumentNullException(nameof(predicate));
×
141
        }
142

143
        return type.GetCustomAttributes<TAttribute>(inherit: true).Where(predicate).ToArray();
8✔
144
    }
8✔
145

146
    /// <summary>
147
    /// Returns <see langword="true" /> if the type overrides the Equals method, or <see langword="false" /> otherwise.
148
    /// </summary>
149
    public static bool OverridesEquals(this Type type)
150
    {
4✔
151
        MethodInfo method = type
4✔
152
            .GetMethod("Equals", [typeof(object)]);
4✔
153

154
        return method is not null
4!
155
               && method.GetBaseDefinition().DeclaringType != method.DeclaringType;
4✔
156
    }
4✔
157

158
    /// <summary>
159
    /// Determines whether the actual type is the same as, or inherits from, the expected type.
160
    /// </summary>
161
    /// <remarks>
162
    /// The expected type can also be an open generic type definition.
163
    /// </remarks>
164
    /// <returns><see langword="true" /> if the actual type is the same as, or inherits from, the expected type; otherwise, <see langword="false" />.</returns>
165
    public static bool IsSameOrInherits<TExpectedType>(this Type actualType)
166
    {
12✔
167
        return actualType.IsSameOrInherits(typeof(TExpectedType));
12✔
168
    }
12✔
169

170
    /// <summary>
171
    /// Determines whether the actual type is the same as, or inherits from, the expected type.
172
    /// </summary>
173
    /// <remarks>
174
    /// The expected type can also be an open generic type definition.
175
    /// </remarks>
176
    /// <returns><see langword="true" /> if the actual type is the same as, or inherits from, the expected type; otherwise, <see langword="false" />.</returns>
177
    public static bool IsSameOrInherits(this Type actualType, Type expectedType)
178
    {
24✔
179
        return actualType == expectedType ||
24✔
180
               expectedType.IsAssignableFrom(actualType) ||
24✔
181
               (actualType.BaseType is { IsGenericType: true } && actualType.BaseType.GetGenericTypeDefinition() == expectedType);
24✔
182
    }
24✔
183

184
    /// <summary>
185
    /// Returns <see langword="true" /> if the type is a delegate type; otherwise, <see langword="false" />.
186
    /// </summary>
187
    public static bool IsDelegate(this Type type)
188
    {
6✔
189
        return typeof(Delegate).IsAssignableFrom(type);
6✔
190
    }
6✔
191

192
    /// <summary>
193
    /// Returns <see langword="true" /> if the type is a compiler-generated type, or <see langword="false" /> otherwise.
194
    /// </summary>
195
    /// <remarks>
196
    /// Typical examples of compiler-generated types are anonymous types, tuples, and records.
197
    /// </remarks>
198
    public static bool IsCompilerGenerated(this Type type)
199
    {
10✔
200
        return type.HasAttribute<CompilerGeneratedAttribute>() ||
10✔
201
               type.IsRecord() ||
10✔
202
               type.IsTuple();
10✔
203
    }
10✔
204

205
    /// <summary>
206
    /// Returns <see langword="true" /> if the type has a readable name, or <see langword="false" />
207
    /// if it is a compiler-generated name.
208
    /// </summary>
209
    public static bool HasFriendlyName(this Type type)
210
    {
6✔
211
        return !type.IsAnonymous() && !type.IsTuple();
6✔
212
    }
6✔
213

214
    /// <summary>
215
    /// Return <see langword="true" /> if the type is a tuple type; otherwise, <see langword="false" />
216
    /// </summary>
217
    public static bool IsTuple(this Type type)
218
    {
14✔
219
        if (!type.IsGenericType)
14✔
220
        {
6✔
221
            return false;
6✔
222
        }
223

224
#if NETCOREAPP2_0_OR_GREATER || NET471_OR_GREATER || NETSTANDARD2_1_OR_GREATER
225
        return typeof(ITuple).IsAssignableFrom(type);
8✔
226
#else
227
        Type openType = type.GetGenericTypeDefinition();
228

229
        return openType == typeof(ValueTuple<>)
230
               || openType == typeof(ValueTuple<,>)
231
               || openType == typeof(ValueTuple<,,>)
232
               || openType == typeof(ValueTuple<,,,>)
233
               || openType == typeof(ValueTuple<,,,,>)
234
               || openType == typeof(ValueTuple<,,,,,>)
235
               || openType == typeof(ValueTuple<,,,,,,>)
236
               || (openType == typeof(ValueTuple<,,,,,,,>) && IsTuple(type.GetGenericArguments()[7]))
237
               || openType == typeof(Tuple<>)
238
               || openType == typeof(Tuple<,>)
239
               || openType == typeof(Tuple<,,>)
240
               || openType == typeof(Tuple<,,,>)
241
               || openType == typeof(Tuple<,,,,>)
242
               || openType == typeof(Tuple<,,,,,>)
243
               || openType == typeof(Tuple<,,,,,,>)
244
               || (openType == typeof(Tuple<,,,,,,,>) && IsTuple(type.GetGenericArguments()[7]));
245
#endif
246
    }
14✔
247

248
    /// <summary>
249
    /// Returns <see langword="true" /> if the type is an anonymous type, or <see langword="false" /> otherwise.
250
    /// </summary>
251
    public static bool IsAnonymous(this Type type)
252
    {
12✔
253
        if (!type.FullName!.Contains("AnonymousType"))
12✔
254
        {
8✔
255
            return false;
8✔
256
        }
257

258
        return type.HasAttribute<CompilerGeneratedAttribute>();
4✔
259
    }
12✔
260

261
    /// <summary>
262
    /// Return <see langword="true" /> if the type is a struct or class record type; otherwise, <see langword="false" />.
263
    /// </summary>
264
    public static bool IsRecord(this Type type)
265
    {
12✔
266
        return type.IsRecordClass() || type.IsRecordStruct();
12✔
267
    }
12✔
268

269
    /// <summary>
270
    /// Returns <see langword="true" /> if the type is a class record type; otherwise, <see langword="false" />.
271
    /// </summary>
272
    public static bool IsRecordClass(this Type type)
273
    {
18✔
274
        return type.GetMethod("<Clone>$", BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) is { } &&
18!
275
               type.GetProperty("EqualityContract", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly)?
18✔
276
                   .GetMethod?.HasAttribute<CompilerGeneratedAttribute>() == true;
18✔
277
    }
18✔
278

279
    /// <summary>
280
    /// Return <see langword="true" /> if the type is a record struct; otherwise, <see langword="false" />
281
    /// </summary>
282
    public static bool IsRecordStruct(this Type type)
283
    {
16✔
284
        // As noted here: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-10.0/record-structs#open-questions
285
        // recognizing record structs from metadata is an open point. The following check is based on common sense
286
        // and heuristic testing, apparently giving good results but not supported by official documentation.
287
        return type.BaseType == typeof(ValueType) &&
16!
288
               type.GetMethod("PrintMembers", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly, null,
16✔
289
                   [typeof(StringBuilder)], null) is { } &&
16✔
290
               type.GetMethod("op_Equality", BindingFlags.Static | BindingFlags.Public | BindingFlags.DeclaredOnly, null,
16✔
291
                       [type, type], null)?
16✔
292
                   .HasAttribute<CompilerGeneratedAttribute>() == true;
16✔
293
    }
16✔
294

295
    /// <summary>
296
    /// Determines whether the specified type is a KeyValuePair.
297
    /// </summary>
298
    /// <param name="type">The type to check.</param>
299
    /// <returns><see langword="true" /> if the type is a KeyValuePair; otherwise, <see langword="false" />.</returns>
300
    public static bool IsKeyValuePair(this Type type)
301
    {
14✔
302
        return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(KeyValuePair<,>);
14✔
303
    }
14✔
304

305
    /// <summary>
306
    /// Returns <see langword="true" /> if the type is a struct (i.e., a value type that is not an enum);
307
    /// otherwise, <see langword="false" />.
308
    /// </summary>
309
    public static bool IsStruct(this Type type)
310
    {
8✔
311
        return type.IsValueType && !type.IsEnum;
8✔
312
    }
8✔
313

314
    /// <summary>
315
    /// Returns <see langword="true" /> if the type is a ref struct; otherwise, <see langword="false" />.
316
    /// </summary>
317
    /// <remarks>
318
    /// Returns <see langword="false" /> on .NET versions that do not support ref structs.
319
    /// </remarks>
320
    public static bool IsRefStruct(this Type type)
321
    {
8✔
322
#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
323
        return type.IsDefined(typeof(IsByRefLikeAttribute), false);
8✔
324
#else
325
        return false;
326
#endif
327
    }
8✔
328
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc