除非我添加ToList(),否则为什么在foreach中对Linq分组选择所做的更改会被忽略? [英] Why do changes made in foreach to a Linq grouping select get ignored unless I add ToList()?

查看:41
本文介绍了除非我添加ToList(),否则为什么在foreach中对Linq分组选择所做的更改会被忽略?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下方法.

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 CalculatedValues are null. However if I add a ToList() to the Select sentence after the GroupBy the CalculatedValues 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屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆