C# 为什么在foreach中对Linq分组select所做的更改会被忽略,除非我添加ToList()?
我有以下方法C# 为什么在foreach中对Linq分组select所做的更改会被忽略,除非我添加ToList()?,c#,linq,linq-group,C#,Linq,Linq Group,我有以下方法 public IEnumerable<Item> ChangeValueIEnumerable() { var items = new List<Item>(){ new Item("Item1", 1), new Item("Item2", 1), new Item("Item3", 2), new Item("Item4", 2),
public IEnumerable<Item> ChangeValueIEnumerable()
{
var items = new List<Item>(){
new Item("Item1", 1),
new Item("Item2", 1),
new Item("Item3", 2),
new Item("Item4", 2),
new Item("Item5", 3)
};
var groupedItems = items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key));
foreach (var item in groupedItems)
{
item.CalculatedValue = item.Name + item.Value;
}
return groupedItems;
}
所以,问题是。为什么会这样?我想知道原因,我的解决方案是添加一个ToList()
更新:项
类的定义如下
public class Item
{
public string Name { get; set; }
public int Value { get; set; }
public string CalculatedValue { get; set; }
public Item(string name, int value)
{
this.Name = name;
this.Value = value;
}
}
在这里,groupedItems
实际上并不包含任何项目。Select
返回的IEnumerable
表示一个计算-准确地说,它表示通过应用函数x=>newitem(x.First().Name,x.Key)
将items
映射到一组新项的结果
每次迭代groupedItems
,都将应用该函数并创建一组新项
var groupedItems = items.GroupBy(i => i.Value)
.Select(x =>
{
Console.WriteLine("Creating new item");
return new Item(x.First().Name, x.Key));
}
foreach(var item in groupedItems);
foreach(var item in groupedItems);
例如,此代码将为items
中的每个项目打印两次“创建新项目”
在代码中,您正在设置临时项目的CalculatedValue
。当foreach循环完成时,项目就消失了
通过调用ToList
,您将“计算”转化为实际的项目集合
除了调用ToList
,您还可以创建另一个计算,用CalculatedValue
属性集表示一组新的项。这是功能性的方式
如果你想对包含计算的对象这一主题做更多的研究,用谷歌搜索术语“Monad”,但要做好混淆的准备。只是为了补充dcastro的好答案,即对
for
循环中的项所做的更改(突变)发生在groupedItems
的第一次迭代中,如果ChangeValueIEnumerable
的调用者迭代返回的IEnumerable
,原始groupedItems
将再次执行
请注意,不使用ToList()
就可以通过在Select
中进行投影来避免此问题:
var groupedItems = items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key)
{
CalculatedValue = x.First().Name + x.Key
});
return groupedItems;
你能发布
项目的定义吗?@Enigmativity我已经添加了项目类。另一方面,按照惯例,由于项接受构造函数参数,您应该考虑标记关联属性<代码>名称<代码>和<代码>值<代码> >代码>私有集合 >,甚至更好,使用readonly
支持字段来表示不变性。我修改了我的答案,大致与您发布答案的时间相同:)+1
var groupedItems = items.GroupBy(i => i.Value)
.Select(x =>
{
Console.WriteLine("Creating new item");
return new Item(x.First().Name, x.Key));
}
foreach(var item in groupedItems);
foreach(var item in groupedItems);
Func<Item, Item> withCalculatedValue =
item => {
item.CalculatedValue = item.Name + item.Value;
return item;
};
return items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key))
.Select(withCalculatedValue);
return items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key) { CalculatedValue = x.First().Name + x.Key });
var groupedItems = items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key)
{
CalculatedValue = x.First().Name + x.Key
});
return groupedItems;