枚举器行为变化基于我们如何引用它? [英] Enumerator behavior changes based on how we reference it?
问题描述
在类中包装对列表枚举器的引用似乎会改变其行为.带有匿名类的示例:
Wrapping a reference to the list's enumerator inside a class seems to change its behavior. Example with an anonymous class:
public static void Main()
{
var list = new List<int>() { 1, 2, 3 };
var an = new { E = list.GetEnumerator() };
while (an.E.MoveNext())
{
Debug.Write(an.E.Current);
}
}
我希望它打印"123",但它只打印零,并且永不终止.带有具体类的相同示例:
I would expect this to print "123", but it only prints zero and never terminates. The same example with a concrete class:
public static void Main()
{
var list = new List<int>() { 1, 2, 3 };
var an = new Foo()
{
E = list.GetEnumerator()
};
while (an.E.MoveNext())
{
Debug.Write(an.E.Current);
}
}
public class Foo
{
public List<int>.Enumerator E { get; set; }
}
这是怎么回事?
推荐答案
我测试了它,对我来说,它也不适用于您的具体课程.
I tested it and for me it does not work with your concrete class either.
原因是List<T>.Enumerator
是可变 struct
,而an.E
是属性.
编译器会为每个自动属性生成一个后备字段,如下所示:
The compiler generates a backing field for each auto-property like this:
public class Foo
{
private List<int>.Enumerator _E;
public List<int>.Enumerator get_E() { return E; }
public void set_E(List<int>.Enumerator value) { E = value; }
}
struct
是一种值类型,因此,每次访问an.E
时,都会得到该值的副本.
A struct
is a value-type, so every-time you access an.E
you get a copy of that value.
当您调用MoveNext()
或Current
时,您在该副本的上调用它,并且此副本已被突变.
When you call MoveNext()
or Current
, you call it on that copy and this copy is mutated.
下次访问an.E
呼叫MoveNext()
或Current
时,您会得到尚未迭代的枚举器的新副本.
The next time you access an.E
to call MoveNext()
or Current
you get a fresh copy of the not-yet-iterated enumerator.
an.E.Current
是0
而不是1
,因为-再次-您获得了尚未调用MoveNext()
的新鲜枚举器.
And an.E.Current
is 0
instead of 1
because - again - you get a fresh enumerator that MoveNext()
was not yet called upon.
如果要存储列表的枚举数的引用,则可以使用类型为IEnumerator<int>
的属性声明类Foo
:
If you want to store a reference of the list's enumerator you could declare your class Foo
with a property of type IEnumerator<int>
:
public class Foo
{
public IEnumerator<int> E { get; set; }
}
如果立即分配E = list.GetEnumerator();
,则枚举器将被装箱并存储引用而不是 value .
If you assign E = list.GetEnumerator();
now, the enumerator gets boxed and a reference instead of a value is stored.
这篇关于枚举器行为变化基于我们如何引用它?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!