Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么在foreach中对Linq分组select所做的更改会被忽略,除非我添加ToList()?_C#_Linq_Linq Group - Fatal编程技术网

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;