枚举器行为会根据我们的引用方式而改变吗?

在类中包含对列表枚举器的引用似乎改变了它的行为。 匿名类的示例:

public static void Main() { var list = new List() { 1, 2, 3 }; var an = new { E = list.GetEnumerator() }; while (an.E.MoveNext()) { Debug.Write(an.E.Current); } } 

我希望这打印“123”,但它只打印零,永远不会终止。 具体类的相同示例:

 public static void Main() { var list = new List() { 1, 2, 3 }; var an = new Foo() { E = list.GetEnumerator() }; while (an.E.MoveNext()) { Debug.Write(an.E.Current); } } public class Foo { public List.Enumerator E { get; set; } } 

这是怎么回事?

我对它进行了测试,对我而言,它也不适用于您的具体课程。

原因是List.Enumerator是一个可变 structan.E是一个属性

编译器为每个自动属性生成一个支持字段,如下所示:

 public class Foo { private List.Enumerator _E; public List.Enumerator get_E() { return E; } public void set_E(List.Enumerator value) { E = value; } } 

struct是值类型,因此每次访问an.E您都会获得该值的副本

当您调用MoveNext()Current ,您可以在该副本上调用它并且此副本会发生变异。

下次访问an.E以调用MoveNext()Current您将获得尚未迭代的枚举器新副本

并且an.E.Current0而不是1因为 – 再次 – 你得到一个新的枚举器, MoveNext()尚未被调用。


如果要存储列表枚举器的引用 ,可以使用IEnumerator类型的属性声明类Foo

 public class Foo { public IEnumerator E { get; set; } } 

如果你指定E = list.GetEnumerator(); 现在,枚举器被装箱并存储引用而不是