枚举器行为的变化基于我们如何引用它?
Enumerator behavior changes based on how we reference it?
将对列表枚举器的引用包装在 class 中似乎改变了它的行为。匿名示例 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”,但它只打印零并且永远不会终止。同一个具体的例子 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; }
}
怎么回事?
我测试了它,对我来说它也不适用于你的混凝土 class。
原因是 List<T>.Enumerator
是一个 可变的 struct
而 an.E
是一个 属性 .
编译器为每个 auto-属性 生成一个支持字段,如下所示:
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; }
}
A struct
是一种值类型,因此每次访问 an.E
时,您都会得到该值的 copy。
当您调用 MoveNext()
或 Current
时,您在 那个副本 上调用它,并且这个副本发生了变异。
下次您访问 an.E
以调用 MoveNext()
或 Current
时,您会得到一个 尚未迭代的枚举器的新副本 .
并且 an.E.Current
是 0
而不是 1
因为 - 再一次 - 你得到一个新的枚举器 MoveNext()
还没有被调用。
如果您想存储列表枚举器的 reference,您可以使用 属性 类型声明 class Foo
IEnumerator<int>
:
public class Foo
{
public IEnumerator<int> E { get; set; }
}
如果您现在分配 E = list.GetEnumerator();
,枚举器将被装箱并存储 reference 而不是 value。
将对列表枚举器的引用包装在 class 中似乎改变了它的行为。匿名示例 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”,但它只打印零并且永远不会终止。同一个具体的例子 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; }
}
怎么回事?
我测试了它,对我来说它也不适用于你的混凝土 class。
原因是 List<T>.Enumerator
是一个 可变的 struct
而 an.E
是一个 属性 .
编译器为每个 auto-属性 生成一个支持字段,如下所示:
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; }
}
A struct
是一种值类型,因此每次访问 an.E
时,您都会得到该值的 copy。
当您调用 MoveNext()
或 Current
时,您在 那个副本 上调用它,并且这个副本发生了变异。
下次您访问 an.E
以调用 MoveNext()
或 Current
时,您会得到一个 尚未迭代的枚举器的新副本 .
并且 an.E.Current
是 0
而不是 1
因为 - 再一次 - 你得到一个新的枚举器 MoveNext()
还没有被调用。
如果您想存储列表枚举器的 reference,您可以使用 属性 类型声明 class Foo
IEnumerator<int>
:
public class Foo
{
public IEnumerator<int> E { get; set; }
}
如果您现在分配 E = list.GetEnumerator();
,枚举器将被装箱并存储 reference 而不是 value。