C # .NET Unexpected text input - advanced foreach description

As I was reviewing the code yesterday, I noticed some strange behavior. I repeated the set of types A The declaration and use of Enumerable were separated (I declared and defined a variable using some Linq, and then iterated through it later through foreach). However, when I changed the type of the enumeration from IEnumerable<A> to IEnumerable<B> , I left foreach next, where the enumerated was of type IEnumerable<B> .

 IEnumerable<B> enumerable = someEnumerableOfB foreach(A a in enumerable) 

The following is a far-fetched example of the behavior I found:

  IEnumerable<IEnumerable> enumerables = Enumerable.Range(1, 5).Select(x => new List<int> { x }); foreach (StringComparer i in enumerables) //this compiles { //do something here } foreach (int i in enumerables) //this doesn't compile { //do something here } IEnumerable<StringBuilder> stringBuilders = Enumerable.Range(1, 5).Select(x => new StringBuilder(x.ToString())); foreach (FileStream sb in stringBuilders) //this doesn't compile { //do something here } 

I was surprised to see the first compile. Can someone explain why this works? I assume this has something to do with IEnumerable having an interface, but I can't explain it.

+4
source share
2 answers

According to the algorithm described in section 15.8.4. specification , the compiler will extend foreach to the following:

 { IEnumerator<IEnumerable> e = ((IEnumerable<IEnumerable>)(x)).GetEnumerator(); try { StringComparer v; while (e.MoveNext()) { v = (StringComparer)(IEnumerable)e.Current; // (*) // do something here } } finally { // Dispose of e } } 

The line marked with an asterisk is the reason for its compilation for the first, and not for the second. This is a valid action because you may have a subclass of StringComparer that implements IEnumerable . Now change it to:

 v = (int)(IEnumerable)e.Current; // (*) 

And it does not compile because it is an invalid listing: int does not implement IEnumerable , and it cannot have any subclasses.

+4
source

Since the compiler does not know what is going on in Enumerable, but it knows that it cannot be a value type (e.g. int).

foreach (StringComparer i in enumerated numbers) will be compiled, since StringComparer is a reference type, and for compilers it can just be enumerated.

+1
source

Source: https://habr.com/ru/post/1347577/


All Articles