首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Enumerator.MoveNext()的奇异行为

Enumerator.MoveNext()的奇异行为
EN

Stack Overflow用户
提问于 2015-07-23 15:05:03
回答 2查看 2.9K关注 0票数 35

有人能解释一下为什么这段代码在无穷大循环中运行吗?为什么MoveNext()总是返回true

代码语言:javascript
复制
var x = new { TempList = new List<int> { 1, 3, 6, 9 }.GetEnumerator() };
while (x.TempList.MoveNext())
{
  Console.WriteLine("Hello World");
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-07-23 15:08:28

List.GetEnumerator()返回可变值类型(List.Enumerator)。您将该值存储在匿名类型中。

现在,让我们来看看它的作用:

代码语言:javascript
复制
while (x.TempList.MoveNext())
{
    // Ignore this
}

这相当于:

代码语言:javascript
复制
while (true)
{
    var tmp = x.TempList;
    var result = tmp.MoveNext();
    if (!result)
    {
        break;
    }

    // Original loop body
}

现在请注意我们在什么上调用MoveNext() --匿名类型中的值的副本。实际上,您不能更改匿名类型中的值--您所拥有的只是一个可以调用的属性,它将给您一个值的副本。

如果将代码更改为:

代码语言:javascript
复制
var x = new { TempList = (IEnumerable<int>) new List<int> { 1, 3, 6, 9 }.GetEnumerator() };

..。然后,您将得到匿名类型的引用。对包含可变值的框的引用。当您对该引用调用MoveNext()时,框内的值将发生变化,因此它将执行您想要的操作。

有关非常类似的情况(同样使用List<T>.GetEnumerator())的分析,请参见my 2010 blog post "Iterate, damn you!"

票数 41
EN

Stack Overflow用户

发布于 2015-07-23 22:14:53

虽然C#中的C#构造和VB.NET中的For Each循环经常与实现IEnumerable<T>的类型一起使用,但它们将接受包含返回类型提供适当的MoveNext函数和Current属性的GetEnumerator方法的任何类型。让GetEnumerator返回值类型在许多情况下将允许foreach比返回IEnumerator<T>时更有效地实现。

不幸的是,由于类型在从foreach调用时无法提供值类型枚举数,而在通过GetEnumerator方法调用时也不能提供值类型枚举器,因此List<T>的作者在性能和语义上面临着轻微的权衡。当时,由于C#不支持变量类型推断,任何使用从List<T>.GetEnumerator返回的值的代码都必须声明一个类型为IEnumerator<T>List<T>.Enumerator的变量。使用前一种类型的代码表现得好像List<T>.Enumerator是一种引用类型,而使用后者的程序员可能会意识到它是一种结构类型。然而,当C#添加类型推断时,这个假设就不再成立了。代码很容易使用List<T>.Enumerator类型,而程序员不知道该类型的存在。

如果C#定义了一个structures属性,该属性可以用于标记不应该在只读结构上调用的方法,如果List<T>.Enumerator使用了它,那么像您这样的代码在调用MoveNext时会正确地产生编译时错误,而不是产生虚假行为。然而,我不知道有什么特别的计划来添加这样的属性。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31591238

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档