What's going on behind the scene of the 'foreach' loop? [duplicate]

和自甴很熟 提交于 2019-11-29 09:35:31
Eric Lippert

I encourage you to read section 8.8.4 of the C# specification, which answers your question in detail. Quoting from it here for your convenience:


A foreach statement of the form

foreach (V v in x) embedded-statement

is then expanded to:

{
    E e = ((C)(x)).GetEnumerator();
    try 
    {
        V v;
        while (e.MoveNext()) 
        {
            v = (V)(T)e.Current;
            embedded-statement
        }
    }
    finally 
    {
         code to Dispose e if necessary
    }
}

The types E, C, V and T are the enumerator, collection, loop variable and collection element types deduced by the semantic analyzer; see the spec for details.

So there you go. A "foreach" is just a more convenient way of writing a "while" loop that calls MoveNext until MoveNext returns false.

A few subtle things:

  • This need not be the code that is generated; all that is required is that we generate code that produces the same result. For example, if you "foreach" over an array or a string, we just generate a "for" loop (or loops, in the case of multi-d arrays) that indexes the array or the chars of the string, rather than taking on the expense of allocating an enumerator.

  • If the enumerator is of value type then the disposal code might or might not choose to box the enumerator before disposing it. Don't rely on that one way or the other. (See http://blogs.msdn.com/b/ericlippert/archive/2011/03/14/to-box-or-not-to-box-that-is-the-question.aspx for a related issue.)

  • Similarly, if the casts automatically inserted above are determined to be identity conversions then the casts might be elided even if doing so would normally cause a value type to be copied.

  • Future versions of C# are likely to put the declaration of loop variable v inside the while loop body; this will prevent the common "modified closure" bug that is reported about once a day on Stack Overflow. [Update: This change has indeed been implemented in C# 5.]

Consider it like this:

 var enumerator = <YourEnumerableHere>.GetEnumerator();

 while(enumerator.MoveNext())
    <YourForEachMethodBodyHere>

Ergo, when it calls GetEnumerator, you get back that result to the PeopleEnum. Every time the MoveNext method is called, the PeopleEnum's position increases by one, iterating over the list.

When the position has reached the end, the MoveNext call returns false, and the loop ends.

It knows to iterate through the IEnumerable because that is what the language designers decided foreach should do. foreach is providing you a shorthand way of looping through an IEnumerable yourself.

The IEnumerator class is defining what it means to "get the next element". If you wanted to, you could make the IEnumerator return every other element, but most people just want to go through each element sequentially.

I am not sure if I have answered your question. If not, let me know and I will respond.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!