2009-04-15 26 views
6

昨天我写了下面的C#代码(缩短一点的可读性):为什么我不能在for循环中更改linq IEnumerable中的元素?

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

因此,每个项目都有一个开始时间和一些有一个结束时间(其他有null作为结束时间)。

如果同时开始和结束时间是已知的,我想计算经过时间:

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) 

它的工作。

我非常想知道这是为什么?

回答

11

您的timeObjects是延迟执行的枚举。如果列举两次列表,结果将被实际评估两次,从而创建新对象。

当您执行ToList()时,它创建了该查询的结果的一个本地副本/ enumerable,这就是您看到更改的原因。这种LINQ查询不会在封面下创建任何种类的列表。查询本身不会执行,直到您列举它。你所做的(从......选择)状态是创建查询定义。

1

您的原始timeObjects定义定义了一个获得懒惰评估的LINQ表达式,因此每次尝试遍历timeObjects可枚举时,它都会创建MyObject的新实例。

-1

它似乎直到调用ToList()它不是IEnumerable但IQueryable,所以对临时对象进行更改。

相关问题