IEnumerable中的项目已在foreach中更改,但更改未保存到集合中 [英] Item from IEnumerable changed inside foreach, but change not saved to collection

查看:69
本文介绍了IEnumerable中的项目已在foreach中更改,但更改未保存到集合中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我今天有一个有趣的问题,这是复制品:

I had an interesting problem today, this is a reproduction:

class TestListAndEnumerable
{
    public static void Test()
    {
        bool b1 = GetBool1(); // returns false
        bool b2 = GetBool2(); // returns true
    }

    private static bool GetBool1()
    {
        IEnumerable<BoolContainer> list = new List<bool> { false }.Select(x => new BoolContainer { Value = x });

        foreach (BoolContainer item in list)
        {
            item.Value = true;
        }

        return list.Select(x => x.Value).First();
    }

    private static bool GetBool2()
    {
        List<BoolContainer> list = new List<bool> { false }.Select(x => new BoolContainer { Value = x }).ToList();

        foreach (BoolContainer item in list)
        {
            item.Value = true;
        }

        return list.Select(x => x.Value).First();
    }

    private class BoolContainer
    {
        public bool Value { get; set; }
    }
}

GetBool1()内部,更改item的值对list变量没有影响.
GetBool2()可以正常工作.

Inside GetBool1(), changing the value of item has no effect on the list variable.
GetBool2() works as expected.

有人知道为什么会这样吗?

Anyone know why this is happening?

[关于重复标签]

我认为这与此问题基本上是相同的问题,但是这里的问题更加简洁,点,所以我就离开它.

I think it IS fundamentally the same problem as in this question, but the question here is more concise and to the point so I'll leave it.

推荐答案

这是LINQ的懒惰评估问题.每次在GetBool1()中的list上进行迭代时,都会创建一个新的值序列.更改其中一个对象的Value属性不会更改其他任何内容.

This is a matter of LINQ's lazy evaluation. Each time you iterate over list in GetBool1(), you're creating a new sequence of values. Changing the Value property in one of those objects doesn't change anything else.

将其与GetBool2()进行比较,在那里您可以调用ToList(),这意味着您将创建一个包含一系列对象的List<T>.现在,每次迭代该列表时,您都会将会获得对相同对象的引用...因此,如果您在这些对象之一中修改值,则下次会看到该值.

Compare that with GetBool2(), where you're got a call to ToList(), which means you're creating a List<T> with a sequence of objects in. Now each time you iterate over that list, you'll get references to the same objects... so if you modify the value within one of those objects, you'll see that next time.

如果将Select argument更改为

x => {Console.WriteLine("Selecting!");返回新的BoolContainer {Value = x}};

x => { Console.WriteLine("Selecting!"); return new BoolContainer { Value = x } };

...然后添加适当的额外Console.WriteLine调用,这样您就可以看到调用发生的时间,您会看到在调用ToList()之后,从未在GetBool2()中调用委托,而在GetBool1()中每次您迭代序列时都会调用它.

... then add appropriate extra Console.WriteLine calls so you can see when it's taking place, you'll see that the delegate is never called in GetBool2() after the call to ToList(), but in GetBool1() it will be called each time you iterate over the sequence.

这篇关于IEnumerable中的项目已在foreach中更改,但更改未保存到集合中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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