You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Enumerator的MoveNext()导致循环挂起?两种写法差异探究

为什么第一段代码会出现循环挂起?

先看这段会导致循环挂起的代码:

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

while (x.Items.MoveNext())
   Console.WriteLine(x.Items.Current);

而这段代码能正常遍历列表:

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

var enumerator = x.Items.GetEnumerator();

while (enumerator.MoveNext())
   Console.WriteLine(enumerator.Current);

反编译后的代码如下:

List<int> intList = new List<int>();
intList.Add(1);
intList.Add(2);
intList.Add(3);
var data1 = new <>f__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 <>f__AnonymousType0<List<int>>(Items);
List<int>.Enumerator enumerator = data2.Items.GetEnumerator();
while (enumerator.MoveNext())
   Console.WriteLine(enumerator.Current);

问题根源

核心原因是**List<T>.Enumerator是值类型(struct)**,而非引用类型(class)。

在第一段代码中,匿名类型的Items字段存储的是这个值类型枚举器的实例。每次访问x.Items时,都会返回该枚举器的全新副本:

  1. 第一次调用x.Items.MoveNext(),是在副本A上执行操作,副本A的状态前进到第一个元素;
  2. 接着调用x.Items.Current,会创建新的副本B——这个副本B仍处于初始未遍历状态,因此Current返回默认值0;
  3. 下一轮循环再次访问x.Items.MoveNext(),又会拿到新的副本C,执行MoveNext后状态再次前进到第一个元素,永远无法触发枚举结束的条件,循环也就无限挂起。

而第二段代码里,我们将枚举器实例赋值给变量enumerator,后续所有操作都针对同一个枚举器实例,每次MoveNext都会推进它的状态,遍历完所有元素后循环正常终止。

内容的提问来源于stack exchange,提问作者Metaller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 18:20:32