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

NetFabric / NetFabric.CodeAnalysis / 6101088975

06 Sep 2023 06:36PM UTC coverage: 82.932% (+2.0%) from 80.942%
6101088975

push

github

web-flow
Add support for GetEnumerator as an extension method (#26)

* Add support for GetEnumerator as an extension method

* Fixes

224 of 264 branches covered (0.0%)

Branch coverage included in aggregate %.

127 of 127 new or added lines in 16 files covered. (100.0%)

636 of 773 relevant lines covered (82.28%)

17.9 hits per line

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

95.83
/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="errors">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 Errors errors)
29
        {
30
            var forEachUsesIndexer = type.IsArray || type.IsSpanOrReadOnlySpan();
77✔
31

32
            if (!type.IsInterface)
77✔
33
            {
34
                var getEnumerator = type.GetPublicInstanceMethod(nameof(IEnumerable.GetEnumerator), Type.EmptyTypes);
74✔
35
                if (getEnumerator is not null)
74✔
36
                {
37
                    var enumeratorType = getEnumerator.ReturnType;
59✔
38
                    if (enumeratorType.IsInterface)
59✔
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]).GetPublicInstanceDeclaredOnlyReadProperty(nameof(IEnumerator<int>.Current))!,
1✔
47
                                    moveNext: typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes)!)
1✔
48
                                {
1✔
49
                                    Reset = typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(NameOf.Reset, Type.EmptyTypes),
1✔
50
                                    Dispose = typeof(IDisposable).GetPublicInstanceDeclaredOnlyMethod(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).GetPublicInstanceDeclaredOnlyReadProperty(nameof(IEnumerator<int>.Current))!,
7✔
63
                                    moveNext: typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes)!)
7✔
64
                                {
7✔
65
                                    Reset = typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(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
                            errors = Errors.MissingCurrent;
×
75
                            return false;
×
76
                        }
77
                    }
78
                    else
79
                    {
80
                        var current = enumeratorType.GetPublicInstanceReadProperty(nameof(IEnumerator.Current));
51✔
81
                        if (current is null)
51✔
82
                        {
83
                            enumerableInfo = default;
2✔
84
                            errors = Errors.MissingCurrent;
2✔
85
                            return false;
2✔
86
                        }
87

88
                        var moveNext =
49✔
89
                            enumeratorType.GetPublicInstanceMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes);
49✔
90
                        if (moveNext is null)
49✔
91
                        {
92
                            enumerableInfo = default;
1✔
93
                            errors = Errors.MissingMoveNext;
1✔
94
                            return false;
1✔
95
                        }
96

97
                        var reset = enumeratorType.GetPublicInstanceMethod(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
                    errors = Errors.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.GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerable<int>.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]).GetPublicInstanceDeclaredOnlyReadProperty(nameof(IEnumerator<int>.Current))!,
9✔
126
                        moveNext: typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes)!)
9✔
127
                        {
9✔
128
                            Reset = typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(NameOf.Reset, Type.EmptyTypes),
9✔
129
                            Dispose = typeof(IDisposable).GetPublicInstanceDeclaredOnlyMethod(NameOf.Dispose, Type.EmptyTypes),
9✔
130
                            IsGenericsEnumeratorInterface = true,
9✔
131
                        }
9✔
132
                );
9✔
133
                errors = Errors.None; 
9✔
134
                return true;
9✔
135
            }
136

137
            if (type.ImplementsInterface(typeof(IEnumerable), out _))
9✔
138
            {
139
                var getEnumerator = typeof(IEnumerable).GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerable.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).GetPublicInstanceDeclaredOnlyReadProperty(nameof(IEnumerator.Current))!,
8✔
146
                        moveNext: typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(nameof(IEnumerator.MoveNext), Type.EmptyTypes)!)
8✔
147
                        {
8✔
148
                            Reset = typeof(IEnumerator).GetPublicInstanceDeclaredOnlyMethod(NameOf.Reset, Type.EmptyTypes),
8✔
149
                            Dispose = dispose,
8✔
150
                            IsEnumeratorInterface = true,
8✔
151
                        }
8✔
152
                );
8✔
153
                errors = Errors.None; 
8✔
154
                return true;
8✔
155
            }
156

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

© 2025 Coveralls, Inc