枚举器行为会根据我们的引用方式而改变吗?
在类中包含对列表枚举器的引用似乎改变了它的行为。 匿名类的示例:
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
是一个可变 struct
而an.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.Current
是0
而不是1
因为 – 再次 – 你得到一个新的枚举器, MoveNext()
尚未被调用。
如果要存储列表枚举器的引用 ,可以使用IEnumerator
类型的属性声明类Foo
:
public class Foo { public IEnumerator E { get; set; } }
如果你指定E = list.GetEnumerator();
现在,枚举器被装箱并存储引用而不是值 。