How does foreach call GetEnumerator()? Via IEnumerable reference or via…?

后端 未结 3 1767
孤街浪徒
孤街浪徒 2020-12-08 11:00
    static void Main(string[] args)
    {
        List listArray = new List();
        listArray.Add(100);
        foreach (int item in listArr         


        
3条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-08 11:24

    (a) When foreach statement calls listArray's IEnumerable.GetEnumerator() implementation, does it call it via (1) listArray.GetEnumerator() or (2) IEnumerable.GetEnumerator() or (3) IEnumerable.GetEnumerator() ?

    Option (1) is correct. Note that this means that the enumerator returned is an unboxed mutable struct. The GetEnumerator method is documented as returning one of these:

    http://msdn.microsoft.com/en-us/library/x854yt9s.aspx

    The fact that this is a mutable struct has very real effects if you do something foolish like passing around the struct as though it were a reference type; it will be copied by value, not by reference.

    (1) But according to the above excerpt, e is not accesible to my source code, so how would I be able to pass this struct around ( unless I write code that does manually what foreach statement does automatically )?

    You are correct. I was not clear. My point was that if you write code that does what foreach does and you mess with the enumerator object yourself then you have to be careful. The CLR team realized that the vast majority of people would be using the foreach loop and would thereby not be exposed to the hazard of accidentally using the enumerator incorrectly.

    (2) It seems that if we implement GetEnumerator in the class X itself, then Current should also be implemented in the class E itself since the compiler won't bother to check for the explicit interface members in cases where member lookup doesn't produce a match?

    Correct.

    (3) if foreach has to check for IEnumerable interface, then foreach will always use IEnumerator version of Current? Thus, if E explicitly implements IEnumerator version of Current and if it also implements another version of Current in the class itself, the foreach will always call IEnumerable version of Current?

    Correct. If you get to the point where we're looking on the interface then we're going to use the interface.

    (4) What do you mean by "one of these"

    I meant that it will return an instance of the struct.

    (5) according to above, foreach doesn't check what type of elements some user-defined collection actually stores, but instead assumes that the type of elements is the same as the type returned by Current property?

    Correct. It does check that the cast succeeds. For example, if you say

    foreach(int x in myObjects)
    

    where myObjects gives you an enumerator whose Current is of type object, then the loop assumes that each object can be successfully cast to int, and throws an exception at runtime if that is incorrect. But if you say similarly:

    foreach(string x in myInts)
    

    then the compiler will note that if Current returns an int then the collection never contains a string, and will fail to compile the program.

    (b) Similarly, when foreach references object returned by listArray's IEnumerable.GetEnumerator(), does it reference this object via IEnumerator or IEnumerator reference type?

    The question is predicated upon the answer to the first question being option (2). Since the question is predicated upon a falsehood, it cannot be answered sensibly.

提交回复
热议问题