“foreach”循环背后发生了什么?
可能重复:
foreach循环如何在C#中工作?
我一直在网上搜索,我很难找到任何关于C#中foreach
循环幕后真实情况的答案。
我知道这个问题并不真正与实际编码有关,但它困扰着我。 我对OO编程特别是接口很新。 我知道他们是合同,我理解IEnumerable
和IEnumerator
如何工作的 – 或者我认为。
我一直在MSDN上阅读这篇文章: IEnumerable Interface
我理解一切都是如何建立的。 虽然在Main
循环中我怎么有点不清楚foreach
如何知道如何通过_people中的所有值来进行_people
。 怎么知道这个? 它如何通过调用return new PeopleEnum(_people);
跟踪Current
return new PeopleEnum(_people);
?
编辑 :我不知道这是如何完全重复。 是的,它的类似理由和同样的问题正在被问到,但我们正在寻找不同的答案或我想要的答案在前一个问题中没有讨论过。
像foreach(在obj中的int i){…}等等的foreach循环等同于
……“有点”不是我正在寻找的答案。
我鼓励您阅读C#规范的第8.8.4节,它详细解答了您的问题。 为方便起见,请在此处引用:
表格的foreach声明
foreach (V v in x) embedded-statement
然后扩展到:
{ 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 } }
E,C,V和T类型是语义分析器推导出的枚举器,集合,循环变量和集合元素类型; 请参阅规格了解详情。
你去吧 “foreach”只是编写调用MoveNext的“while”循环的一种更方便的方法,直到MoveNext返回false。
一些微妙的事情:
-
这不一定是生成的代码; 所需要的只是我们生成产生相同结果的代码。 例如,如果你在一个数组或一个字符串上“foreach”,我们只生成一个“for”循环(或循环,在多d数组的情况下),索引数组或字符串的字符,而不是以分配枚举器为代价。
-
如果枚举数是值类型,则处置代码可能会也可能不会选择在处理枚举器之前对其进行封装。 不要依赖那种方式。 (有关相关问题,请参阅http://blogs.msdn.com/b/ericlippert/archive/2011/03/14/to-box-or-not-to-box-that-is-the-question.aspx 。 )
-
类似地,如果上面自动插入的强制转换被确定为身份转换,则即使这样做通常会导致复制值类型,也可能省略强制转换。
-
C#的未来版本很可能将循环变量
v
的声明放在 while循环体内; 这将防止在Stack Overflow上每天报告一次的常见“修改后的闭包”错误。 [ 更新: 此更改确实已在C#5中实施 。]
考虑一下这样:
var enumerator = .GetEnumerator(); while(enumerator.MoveNext())
因此,当它调用GetEnumerator
,您PeopleEnum
结果返回给PeopleEnum
。 每次MoveNext
方法时, PeopleEnum
的位置都会增加1,遍历列表。
当位置到达结尾时, MoveNext
调用返回false,循环结束。
它知道迭代IEnumerable
因为这是语言设计者决定foreach
应该做的事情。 foreach
为您提供了一种自行循环IEnumerable
的简写方法。
IEnumerator
类定义了“获取下一个元素”的含义。 如果你愿意,你可以让IEnumerator
返回所有其他元素,但大多数人只想按顺序遍历每个元素。
我不确定我是否回答了你的问题。 如果没有,请告诉我,我会回复。