为什么我不能在for循环中更改linq IEnumerable中的元素?

昨天我写了下面的c#代码(为了易读性而缩短了一点):

var timeObjects = ( from obj in someList where ( obj.StartTime != null ) select new MyObject() { StartTime= obj.StartTime.Value, EndTime = obj.EndTime } ) 

因此每个项目都有一个startTime,而另一些项目有一个EndTime(其他项目的尾数为null)。

如果已知start和endtime,我想计算经过的时间:

 foreach ( var item in timeObjects) { if ( item.EndTime == null ) { item.elapsed = 0; } else { item.elapsed = ( item.EndTime.Value - item.StartTime).Minutes; } } 

但这不起作用! timeObjects集合永远不会改变。

如果我说:

  var timeObjects = ( from obj in someList where ( obj.StartTime != null ) select new MyObject() { StartTime= obj.StartTime.Value, EndTime = obj.EndTime } ).ToList(); foreach ( var item in timeObjects) { if ( item.EndTime == null ) { item.elapsed = 0; } else { item.elapsed = ( item.EndTime.Value - item.StartTime).Minutes; } } //(only change is the ToList() at the end of the linq statement) 

它确实有效。

我非常想知道为什么会这样?

你的timeObjects是一个可枚举的延迟执行。 如果对列表进行两次枚举,则实际将对结果进行两次计算,从而创建新对象。

当您执行ToList()时,它创建了该查询/可枚举的结果的本地副本,这就是您看到更改的原因。 这种LINQ查询不会创建任何类型的列表。 在您枚举查询之前,不会执行查询本身。 你在(from … select)状态下所做的就是创建查询定义。

您的原始timeObjects定义定义了一个延迟评估的LINQ表达式,因此每当您尝试遍历timeObjects可枚举时,它将创建MyObject的新实例。

在调用ToList()之前,它似乎不是IEnumerable而是IQueryable ,因此对临时对象进行了更改。