为什么枚举器 MoveNext() 返回 0

Met*_*ler 7 .net c# ienumerator list

为什么接下来的代码会产生循环挂起?

var x = new
{
    Items = new List<int> { 1, 2, 3 }.GetEnumerator()
};

while (x.Items.MoveNext())
   Console.WriteLine(x.Items.Current);
Run Code Online (Sandbox Code Playgroud)

如果我在 x 初始化后得到枚举器,则一切正常:

var x = new
{
    Items = new List<int> { 1, 2, 3 }
};

var enumerator = x.Items.GetEnumerator();

while (enumerator.MoveNext())
   Console.WriteLine(enumerator.Current);
Run Code Online (Sandbox Code Playgroud)

尝试反编译这两个代码块,但不明白原因:

List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
var data1 = new \u003C\u003Ef__AnonymousType0<List<int>.Enumerator>(intList.GetEnumerator());
while (true)
{
   List<int>.Enumerator items = data1.Items;
   if (items.MoveNext())
   {
     items = data1.Items;
     Console.WriteLine(items.Current);
   }
   else
     break;
}
List<int> Items = new List<int>();
Items.Add(1);
Items.Add(2);
Items.Add(3);
var data2 = new \u003C\u003Ef__AnonymousType0<List<int>>(Items);
List<int>.Enumerator enumerator = data2.Items.GetEnumerator();
while (enumerator.MoveNext())
   Console.WriteLine(enumerator.Current);
Run Code Online (Sandbox Code Playgroud)

Phi*_*mid 6

因为List的枚举器是一个结构体。在第一个示例中,您正在创建一个枚举器对象(在某个地方,可能是堆,无关紧要),每次使用.Items枚举器访问它时,都会将其复制到执行函数中的堆栈上。MoveNext改变它,然后复制的枚举器被丢弃。如果它是一个类,则只会复制/丢弃引用并修改实际数据,但由于它是一个结构,因此您根本不会修改枚举器var x { ... }Enumerator.Current返回 0 因为default(int)为零,但也可能出现异常。

在第二个示例中,您正在为堆栈上的枚举器创建一个插槽,var enumerator = x.Items.GetEnumerator();并且该插槽可以在没有副本的情况下重复访问。