2008-11-25 110 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的第一个位置返回对象的一个​​新实例。