IEnumerable中的项目在foreach中更改,但更改未保存到集合中

mrz*_*zli 3 c# ienumerable

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

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; }
    }
}
Run Code Online (Sandbox Code Playgroud)

在里面GetBool1(),改变值item对list变量没有影响.
GetBool2()按预期工作.

任何人都知道为什么会这样吗?

[关于重复标签]

我认为,它从根本上是同一个问题在这个问题,但这里的问题是更简洁,重点突出,所以我会离开它.

Jon*_*eet 14

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

将其与GetBool2()您调用的地方进行比较ToList(),这意味着您正在List<T>使用一系列对象创建一个.现在每次遍历该列表时,您将获得对相同对象的引用...所以如果你修改其中一个对象中的值,下次你会看到.

如果你改变你Select argument的

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

...然后添加适当的额外Console.WriteLine调用,以便您可以看到它何时发生,您将看到在调用GetBool2()之后从未调用委托ToList(),但是GetBool1()每次遍历序列时都会调用它.