• 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

95.9
/NetFabric.Reflection/Reflection/TypeExtensions.IsEnumerable.cs
1
using System;
2
using System.Collections;
3
using System.Collections.Generic;
4
using System.Diagnostics.CodeAnalysis;
5

6
namespace NetFabric.Reflection;
7

8
public static partial class TypeExtensions
9
{        
10
    /// <summary>
11
    /// Gets a value indicating whether 'foreach' considers <see cref="System.Type"/> to be enumerable.
12
    /// </summary>
13
    /// <param name="type">The <see cref="System.Type"/> to test.</param>
14
    /// <param name="enumerableInfo">If methods returns <c>true</c>, contains information on the methods 'foreach' will use to enumerate.</param>
15
    /// <returns><c>true</c> if 'foreach' considers <see cref="System.Type"/> to be enumerable; otherwise, <c>false</c>.</returns>
16
    public static bool IsEnumerable(this Type type, [NotNullWhen(true)] out EnumerableInfo? enumerableInfo)
17
        => IsEnumerable(type, out enumerableInfo, out _);
×
18

19
    /// <summary>
20
    /// Gets a value indicating whether 'foreach' considers <see cref="System.Type"/> to be enumerable.
21
    /// </summary>
22
    /// <param name="type">The <see cref="System.Type"/> to test.</param>
23
    /// <param name="enumerableInfo">If methods returns <c>true</c>, contains information on the methods 'foreach' will use to enumerate.</param>
24
    /// <param name="error">Gets information on what error caused the method to return <c>false</c>.</param>
25
    /// <returns><c>true</c> if 'foreach' considers <see cref="System.Type"/> to be enumerable; otherwise, <c>false</c>.</returns>
26
    public static bool IsEnumerable(this Type type,
27
        [NotNullWhen(true)] out EnumerableInfo? enumerableInfo,
28
        out IsEnumerableError error)
29
    {
30
        var forEachUsesIndexer = type.IsArray || type.IsSpanOrReadOnlySpan();
78✔
31

32
        if (!type.IsInterface)
78✔
33
        {
34
            var getEnumerator = type.GetMethod(PublicInstance, NameOf.GetEnumerator, Type.EmptyTypes);
75✔
35
            if (getEnumerator is not null)
75✔
36
            {
37
                var enumeratorType = getEnumerator.ReturnType;
60✔
38
                if (enumeratorType.IsInterface)
60✔
39
                {
40
                    if (enumeratorType.ImplementsInterface(typeof(IEnumerator<>), out var enumeratorGenericArguments))
8✔
41
                    {
42
                        enumerableInfo = new EnumerableInfo(
1✔
43
                            forEachUsesIndexer,
1✔
44
                            getEnumerator,
1✔
45
                            new EnumeratorInfo(
1✔
46
                                current: typeof(IEnumerator<>).MakeGenericType(enumeratorGenericArguments[0]).GetReadProperty(PublicInstanceDeclaredOnly, NameOf.Current)!,
1✔
47
                                moveNext: typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.MoveNext, Type.EmptyTypes)!)
1✔
48
                            {
1✔
49
                                Reset = typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.Reset, Type.EmptyTypes),
1✔
50
                                Dispose = typeof(IDisposable).GetMethod(PublicInstanceDeclaredOnly, NameOf.Dispose, Type.EmptyTypes),
1✔
51
                                IsGenericsEnumeratorInterface = true,
1✔
52
                            }
1✔
53
                        );                            
1✔
54
                    }
55
                    else if(enumeratorType.ImplementsInterface(typeof(IEnumerator), out _))
7!
56
                    {
57
                        _ = enumeratorType.IsDisposable(out var dispose, out _);
7✔
58
                        enumerableInfo = new EnumerableInfo(
7✔
59
                            forEachUsesIndexer,
7✔
60
                            getEnumerator,
7✔
61
                            new EnumeratorInfo(
7✔
62
                                current: typeof(IEnumerator).GetReadProperty(PublicInstanceDeclaredOnly, NameOf.Current)!,
7✔
63
                                moveNext: typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.MoveNext, Type.EmptyTypes)!)
7✔
64
                            {
7✔
65
                                Reset = typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.Reset, Type.EmptyTypes),
7✔
66
                                Dispose = dispose,
7✔
67
                                IsEnumeratorInterface = true,
7✔
68
                            }
7✔
69
                        );                            
7✔
70
                    }
71
                    else
72
                    {
73
                        enumerableInfo = default;
×
74
                        error = IsEnumerableError.MissingCurrent;
×
75
                        return false;
×
76
                    }
77
                }
78
                else
79
                {
80
                    var current = enumeratorType.GetReadProperty(PublicInstance, NameOf.Current);
52✔
81
                    if (current is null)
52✔
82
                    {
83
                        enumerableInfo = default;
2✔
84
                        error = IsEnumerableError.MissingCurrent;
2✔
85
                        return false;
2✔
86
                    }
87

88
                    var moveNext =
50✔
89
                        enumeratorType.GetMethod(PublicInstance, NameOf.MoveNext, Type.EmptyTypes);
50✔
90
                    if (moveNext is null || moveNext.ReturnType != typeof(bool))
50✔
91
                    {
92
                        enumerableInfo = default;
2✔
93
                        error = IsEnumerableError.MissingMoveNext;
2✔
94
                        return false;
2✔
95
                    }
96

97
                    var reset = enumeratorType.GetMethod(PublicInstance, NameOf.Reset, Type.EmptyTypes);
48✔
98
                    _ = enumeratorType.IsDisposable(out var dispose, out var isByRefLike);
48✔
99
                    enumerableInfo = new EnumerableInfo(
48✔
100
                        forEachUsesIndexer,
48✔
101
                        getEnumerator,
48✔
102
                        new EnumeratorInfo(current, moveNext)
48✔
103
                        {
48✔
104
                            Reset = reset,
48✔
105
                            Dispose = dispose,
48✔
106
                            IsValueType = getEnumerator.ReturnType.IsValueType,
48✔
107
                            IsByRefLike = isByRefLike,
48✔
108
                        }
48✔
109
                    );
48✔
110
                }
111

112
                error = IsEnumerableError.None;
56✔
113
                return true;
56✔
114
            }
115
        }
116

117
        if (type.ImplementsInterface(typeof(IEnumerable<>), out var enumerableGenericArguments))
18✔
118
        {
119
            var genericType = typeof(IEnumerable<>).MakeGenericType(enumerableGenericArguments[0]);
9✔
120
            var getEnumerator = genericType.GetMethod(NameOf.GetEnumerator, Type.EmptyTypes)!;
9✔
121
            enumerableInfo = new EnumerableInfo(
9✔
122
                forEachUsesIndexer,
9✔
123
                getEnumerator,
9✔
124
                new EnumeratorInfo(
9✔
125
                    current: typeof(IEnumerator<>).MakeGenericType(enumerableGenericArguments[0]).GetReadProperty(PublicInstanceDeclaredOnly, NameOf.Current)!,
9✔
126
                    moveNext: typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.MoveNext, Type.EmptyTypes)!)
9✔
127
                    {
9✔
128
                        Reset = typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.Reset, Type.EmptyTypes),
9✔
129
                        Dispose = typeof(IDisposable).GetMethod(PublicInstanceDeclaredOnly, NameOf.Dispose, Type.EmptyTypes),
9✔
130
                        IsGenericsEnumeratorInterface = true,
9✔
131
                    }
9✔
132
            );
9✔
133
            error = IsEnumerableError.None; 
9✔
134
            return true;
9✔
135
        }
136

137
        if (type.ImplementsInterface(typeof(IEnumerable), out _))
9✔
138
        {
139
            var getEnumerator = typeof(IEnumerable).GetMethod(NameOf.GetEnumerator, Type.EmptyTypes)!;
8✔
140
            _ = getEnumerator.ReturnType.IsDisposable(out var dispose, out _);
8✔
141
            enumerableInfo = new EnumerableInfo(
8✔
142
                forEachUsesIndexer,
8✔
143
                getEnumerator,
8✔
144
                new EnumeratorInfo(
8✔
145
                    current: typeof(IEnumerator).GetReadProperty(PublicInstanceDeclaredOnly, NameOf.Current)!,
8✔
146
                    moveNext: typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.MoveNext, Type.EmptyTypes)!)
8✔
147
                    {
8✔
148
                        Reset = typeof(IEnumerator).GetMethod(PublicInstanceDeclaredOnly, NameOf.Reset, Type.EmptyTypes),
8✔
149
                        Dispose = dispose,
8✔
150
                        IsEnumeratorInterface = true,
8✔
151
                    }
8✔
152
            );
8✔
153
            error = IsEnumerableError.None; 
8✔
154
            return true;
8✔
155
        }
156

157
        enumerableInfo = default;
1✔
158
        error = IsEnumerableError.MissingGetEnumerator;
1✔
159
        return false;
1✔
160
    }
161
}
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