除非我添加ToList(),否则为什么在foreach中对Linq分组选择所做的更改会被忽略? [英] Why do changes made in foreach to a Linq grouping select get ignored unless I add ToList()?
问题描述
我有以下方法.
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;
}
在 groupedItems
集合中, CalculatedValue
s为空.但是,如果我在 GroupBy
之后的 Select
句子中添加 ToList()
,则 CalculatedValue
具有值.例如:
Into the groupedItems
collection the CalculatedValue
s are null. However if I add a ToList()
to the Select
sentence after the GroupBy
the CalculatedValue
s has values.
for example:
var groupedItems = items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key)).ToList();
所以,问题是.为什么是这样?我想知道原因,对我来说解决方案是添加 ToList()
So, the question is. Why is this? I want to know the reason for this, the solution for me is add a ToList()
更新: Item
类的定义如下
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;
}
}
推荐答案
var groupedItems = items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key));
在这里, groupedItems
实际上不包含任何项目.由 Select
返回的 IEnumerable< T>
表示计算-确切地说,它表示将 items
映射到一组新项目的结果通过应用函数 x =>新项目(x.First().名称,x.Key)
.
Here, groupedItems
doesn't actually hold any items. The IEnumerable<T>
returned by Select
represents a computation - to be precise, it represents the result of mapping items
to a new set of items by applying the function x => new Item(x.First().Name, x.Key)
.
每次迭代 groupedItems
时,都会应用该函数并创建一组新的项目.
Each time you iterate over groupedItems
, the function will be applied and a new set of items will be created.
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);
例如,此代码将为项
中的每个项目打印两次正在创建新项目".
This code, for example, will print "Creating new item" twice for each item in items
.
在您的代码中,您正在设置 ephemeral 项目的 CalculatedValue
.当 foreach 循环完成后,项目就消失了.
In your code, you're setting the CalculatedValue
of an ephemeral item. When the foreach loop is done, the items are gone.
通过调用 ToList
,您可以将计算"变成实际的项目集合.
By calling ToList
, you're turning the "computation" into an actual collection of items.
除了调用 ToList
之外,您还可以创建另一种计算,该计算表示具有 CalculatedValue
属性集的一组新项目.这是功能的方式.
Instead of calling ToList
, you could alternatively create another computation that represents a new set of items with their CalculatedValue
property set. This is the functional way.
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);
或者只是使用对象初始化程序
Or simply use object initializers
return items.GroupBy(i => i.Value)
.Select(x => new Item(x.First().Name, x.Key) { CalculatedValue = x.First().Name + x.Key });
如果您想对保存计算的对象进行更多研究,请用Google术语"Monad",但要做好混淆的准备.
If you want to do a little bit more research on the topic of objects that hold computations, google the term "Monad", but be prepared to be confused.
这篇关于除非我添加ToList(),否则为什么在foreach中对Linq分组选择所做的更改会被忽略?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!