2009-04-15 28 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,所以對臨時對象進行更改。

相關問題