2008-11-25 108 views
3

我對C#有很多瞭解,但是這一個讓我感到困惑,Google並沒有提供幫助。爲什麼在枚舉對象上設置屬性不起作用?

我有一個IEnumerable範圍的對象。我想在第一個上設置一個屬性。我這樣做,但是當我修改後列舉了對象的範圍時,我沒有看到我的改變。

這裏的問題的一個很好的例子:

public static void GenericCollectionModifier() 
    { 
     // 1, 2, 3, 4... 10 
     var range = Enumerable.Range(1, 10); 

     // Convert range into SubItem classes 
     var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}); 

     Write(items); // Expect to output 1,2,3,4,5,6,7,8,9,10 

     // Make a change 
     items.First().MagicNumber = 42; 

     Write(items); // Expect to output 42,2,3,4,5,6,7,8,9,10 
     // Actual output: 1,2,3,4,5,6,7,8,9,10 
    } 

    public static void Write(IEnumerable<SubItem> items) 
    { 
     Console.WriteLine(string.Join(", ", items.Select(item => item.MagicNumber.ToString()).ToArray())); 
    } 

    public class SubItem 
    { 
     public string Name; 
     public int MagicNumber; 
    } 

#停止哪些方面C1的被輸出我的「MagicNumber = 42」的變化?有沒有辦法讓我的變化「堅持」,而不做一些時髦的轉換到列表<>或數組?

謝謝! -Mike

回答

8

當你調用優先()它列舉了這段代碼的結果:

Select(i => new SubItem() {Name = "foo", MagicNumber = i}); 

注意,選擇是一個懶惰的枚舉,這意味着只有當你向一個項目做選擇從它(並且它時間你問)。結果不會存儲在任何地方,所以當您調用items.First()時,會得到一個新的SubItem實例。當你將項目傳遞給Write時,它會得到大量新的實例 - 而不是你之前獲得的實例。

如果你想存儲你的選擇的結果,修改它,你需要做的是這樣的:

var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}).ToList(); 
+0

是+1。對於原始問題中定義的`items`,每次`items`被迭代時,創建新的`SubItem`實例。 '.First()`迭代一次,`Write`第二次迭代它。這樣做的另一個結果是(item`仍然和原始問題一樣)`items.First()== items.First()`評估爲`false`。 – 2013-01-28 15:50:06

0

我懷疑是在後臺進行的事情。最有可能的原因是IEnumerables只能迭代一次。

如果在分配給'items'時調用Select()後添加'ToList()',它會起作用嗎?

+0

是的,如果我將它轉換爲列表,它按預期工作。儘管如此,我希望避免這種情況。 – Mike 2008-11-25 14:36:03

+0

IEnumerables不僅可以迭代一次。他們懶惰的評估,以便每次迭代你可能會得到不同的結果。然而,添加ToList()可以解決這個問題。 – 2008-11-25 14:36:23

0

我能想到的唯一的事情就是items.First()將SubItem的副本傳遞給您而不是參考,因此當您設置它時,更改不會通過。

我不得不認爲它與IQueryable只能被迭代一次有關。你可能想嘗試改變這一點:

// Convert range into SubItem classes 
var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}); 

// Convert range into SubItem classes 
var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}).ToList(); 

,看看是否有任何不同的結果。

0

你不能/不應該通過枚舉修改的集合。我很驚訝這不會拋出異常。

+0

集合未被修改,項目內的數據爲 – Mike 2008-11-25 14:42:36

0

.First()是一種方法,而不是屬性。它在Enumerable的第一個位置返回對象的一個​​新實例。