我对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;
}
C#的哪个方面阻止了我的“MagicNumber = 42”输出变化?有没有办法让我的变化“坚持”而不做一些时髦的转换为List&lt;&gt;还是数组?
谢谢! -Mike
答案 0 :(得分:8)
当你调用First()时,它会枚举这段代码的结果:
Select(i => new SubItem() {Name = "foo", MagicNumber = i});
请注意,Select是一个惰性枚举器,这意味着只有当你从中请求一个项目时它才会执行select(并且每隔时间提出它)。结果不存储在任何地方,因此当您调用items.First()时,您将获得一个新的SubItem
实例。然后,当您将项目传递给Write时,它会获得一大堆新的SubItem
实例 - 而不是之前获得的实例。
如果要存储选择的结果并对其进行修改,则需要执行以下操作:
var items = range.Select(i => new SubItem() {Name = "foo", MagicNumber = i}).ToList();
答案 1 :(得分:0)
我怀疑背景会发生什么。最有可能的原因是IEnumerables只能迭代一次。
如果在分配给'items'时调用Select()后添加'ToList()'会有效吗?
答案 2 :(得分: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();
看看是否有任何不同的结果。
答案 3 :(得分:0)
您不能/不应该通过枚举器修改集合。我很惊讶这不会引发异常。
答案 4 :(得分:0)
.First()是一个方法,而不是一个属性。它在Enumerable的第一个位置返回一个新对象实例。