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

NetFabric / NetFabric.CodeAnalysis / 6253798736

20 Sep 2023 08:33PM UTC coverage: 75.653% (-7.5%) from 83.158%
6253798736

Pull #28

github

aalmada
Fixes
Pull Request #28: Add IsIndexable

292 of 404 branches covered (0.0%)

Branch coverage included in aggregate %.

259 of 259 new or added lines in 15 files covered. (100.0%)

693 of 898 relevant lines covered (77.17%)

17.09 hits per line

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

81.76
/NetFabric.Reflection/Reflection/TypeExtensions.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Diagnostics.CodeAnalysis;
4
using System.Numerics;
5
using System.Reflection;
6

7
// ReSharper disable LoopCanBeConvertedToQuery
8

9
namespace NetFabric.Reflection;
10

11
public static partial class TypeExtensions
12
{
13
    /// <summary>
14
    /// Determines whether the specified <see cref="Type"/> implements a specified interface and, if so, provides information about generic type arguments.
15
    /// </summary>
16
    /// <param name="type">The <see cref="Type"/> to check for interface implementation.</param>
17
    /// <param name="interfaceType">The <see cref="Type"/> of the interface to check for implementation.</param>
18
    /// <param name="genericArguments">
19
    /// When the method returns <c>true</c>, this parameter contains an array of <see cref="Type"/> objects representing the generic type arguments
20
    /// that make the implementation of the specified interface. If the type does not implement the interface or if the interface is non-generic,
21
    /// this parameter is set to <c>null</c>.
22
    /// </param>
23
    /// <returns>
24
    ///   <c>true</c> if the specified <see cref="Type"/> implements the specified interface; otherwise, <c>false</c>.
25
    /// </returns>
26
    public static bool ImplementsInterface(this Type type, Type interfaceType, [NotNullWhen(true)] out Type[]? genericArguments)
27
    {
28
        if (!interfaceType.IsGenericType)
139✔
29
        {
30
            genericArguments = Type.EmptyTypes;
94✔
31
            return interfaceType.IsAssignableFrom(type);
94✔
32
        }
33

34
        if (type.IsGenericType && type.GetGenericTypeDefinition() == interfaceType.GetGenericTypeDefinition())
45✔
35
        {
36
            genericArguments = type.GetGenericArguments();
12✔
37
            return true;
12✔
38
        }
39

40
        foreach (var @interface in type.GetInterfaces())
89✔
41
        {
42
            if (ImplementsInterface(@interface, interfaceType, out genericArguments))
16✔
43
                return true;
9✔
44
        }
45

46
        genericArguments = default;
24✔
47
        return false;
24✔
48
    }
49

50
    internal const BindingFlags PublicInstance =
51
        BindingFlags.Public | BindingFlags.Instance;
52
        
53
    internal const BindingFlags PublicInstanceDeclaredOnly =
54
        BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly;
55

56
    internal static PropertyInfo? GetReadIndexer(this Type type, BindingFlags bindingAttr, params Type[] parameterTypes)
57
    {
58
        foreach (var property in type.GetProperties(bindingAttr))
24✔
59
        {
60
            if (property.GetGetMethod() is not null && 
7✔
61
                SequenceEqual(property.GetIndexParameters(), parameterTypes))
7✔
62
            {
63
                return property;
4✔
64
            }
65
        }
66

67
        if (type.IsInterface && !bindingAttr.HasFlag(BindingFlags.DeclaredOnly))
3✔
68
        {
69
            foreach(var @interface in type.GetInterfaces())
3✔
70
            {
71
                var indexer = GetReadIndexer(@interface, bindingAttr, parameterTypes);
1✔
72
                if (indexer is not null)
1!
73
                    return indexer;
1✔
74
            }
75
        }
76

77
        return default;
2✔
78
    }
79

80
    internal static PropertyInfo? GetReadProperty(this Type type, BindingFlags bindingAttr, string name)
81
    {
82
        foreach (var property in type.GetProperties(bindingAttr))
360✔
83
        {
84
            if (property.Name == name && 
118✔
85
            property.GetGetMethod() is not null)
118✔
86
            {
87
                return property;
100✔
88
            }
89
        }
90

91
        if (type.IsInterface && !bindingAttr.HasFlag(BindingFlags.DeclaredOnly))
12✔
92
        {
93
            foreach(var @interface in type.GetInterfaces())
11✔
94
            {
95
                var indexer = GetReadProperty(@interface, bindingAttr, name);
2✔
96
                if (indexer is not null)
2✔
97
                    return indexer;
1✔
98
            }
99
        }
100

101
        return default;
11✔
102
    }
103

104
    internal static MethodInfo? GetMethod(this Type type, BindingFlags bindingAttr, string name, params Type[] types)
105
    {
106
        var method = type.GetMethod(name, bindingAttr, types);
352✔
107
        if (method is not null)
352✔
108
            return method;
262✔
109

110
        if (type.IsInterface && !bindingAttr.HasFlag(BindingFlags.DeclaredOnly))
90!
111
        {
112
            foreach(var @interface in type.GetInterfaces())
×
113
            {
114
                method = GetMethod(@interface, bindingAttr, name);
×
115
                if (method is not null)
×
116
                    return method;
×
117
            }
118
        }            
119

120
        return default;
90✔
121
    }
122

123
    static bool SequenceEqual(ParameterInfo[] parameters, Type[] types)
124
    {
125
        if (parameters.Length != types.Length)
7✔
126
            return false;
2✔
127

128
        // ReSharper disable once LoopCanBeConvertedToQuery
129
        for (var index = 0; index < parameters.Length; index++)
18✔
130
        {
131
            if (parameters[index].ParameterType != types[index])
5✔
132
                return false;
1✔
133
        }
134

135
        return true;
4✔
136
    }
137

138
    /// <summary>
139
    /// Determines whether the specified <see cref="Type"/> represents a <see cref="Span{T}"/> or <see cref="ReadOnlySpan{T}"/>.
140
    /// </summary>
141
    /// <param name="type">The <see cref="Type"/> to check for <see cref="Span{T}"/> or <see cref="ReadOnlySpan{T}"/>.</param>
142
    /// <returns>
143
    ///   <c>true</c> if the specified <see cref="Type"/> represents a <see cref="Span{T}"/> or <see cref="ReadOnlySpan{T}"/>;
144
    ///   otherwise, <c>false</c>.
145
    /// </returns>
146
    public static bool IsSpanOrReadOnlySpan(this Type type)
147
    {
148
        if (type.IsGenericType)
77✔
149
        {
150
            var genericTypeDefinition = type.GetGenericTypeDefinition();
67✔
151
            return genericTypeDefinition == typeof(Span<>) || genericTypeDefinition == typeof(ReadOnlySpan<>);
67✔
152
        }
153

154
        return false;
10✔
155
    }
156

157
    /// <summary>
158
    /// Determines whether the specified <see cref="Type"/> represents an integer type.
159
    /// </summary>
160
    /// <param name="type">The <see cref="Type"/> to check for integer type.</param>
161
    /// <returns>
162
    ///   <c>true</c> if the specified <see cref="Type"/> represents an integer type; otherwise, <c>false</c>.
163
    /// </returns>
164
    /// <remarks>
165
    /// Starting from .NET 7, this method checks if the <see cref="Type"/> implements the <see cref="System.Numerics.IBinaryInteger{T}"/> interface,
166
    /// which indicates support for binary integer operations.
167
    /// </remarks>
168
    public static bool IsIntegerType(this Type type)
169
    {
170
        if (type == typeof(SByte) || 
6!
171
            type == typeof(Byte) || 
6✔
172
            type == typeof(Int16) || 
6✔
173
            type == typeof(UInt16) || 
6✔
174
            type == typeof(Int32) || 
6✔
175
            type == typeof(UInt32) || 
6✔
176
            type == typeof(Int64) || 
6✔
177
            type == typeof(UInt64)) 
6✔
178
        {
179
            return true;
6✔
180
        }
181

182
#if NET7_0_OR_GREATER
183
        if (type.ImplementsInterface(typeof(IBinaryInteger<>), out var arguments) && 
184
            arguments.Length == 1 &&
185
            arguments[0] == type)
186
        {
187
            return true;
188
        }
189
#endif
190

191
        return false;
×
192
    }
193

194
    /// <summary>
195
    /// Determines whether the specified <see cref="Type"/> represents a floating-point numeric type.
196
    /// </summary>
197
    /// <param name="type">The <see cref="Type"/> to check for a floating-point numeric type.</param>
198
    /// <returns>
199
    ///   <c>true</c> if the specified <see cref="Type"/> represents a floating-point numeric type; otherwise, <c>false</c>.
200
    /// </returns>
201
    /// <remarks>
202
    /// Starting from .NET 7, this method compares the <see cref="Type"/> to the <see cref="System.Numerics.IFloatingPoint{T}"/> interface,
203
    /// which indicates support for floating-point numeric operations.
204
    /// </remarks>
205
    public static bool IsFloatingPointType(this Type type)
206
    {
207
        if (type == typeof(Half) || 
×
208
            type == typeof(float) || 
×
209
            type == typeof(double) || 
×
210
            type == typeof(decimal))
×
211
        {
212
            return true;
×
213
        }
214

215
#if NET7_0_OR_GREATER
216
        if (type.ImplementsInterface(typeof(IFloatingPoint<>), out var arguments) && 
217
            arguments.Length == 1 &&
218
            arguments[0] == type)
219
        {
220
            return true;
221
        }
222
#endif
223

224
        return false;
×
225
    }
226

227
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc