更新 IEnumerable 中的项目

Updating items in an IEnumerable

我有这个代码:

   class Foo
    {
        public string A { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var strings = new List<string> { "foo", "foo" };

            var list = strings.Select(x => new Foo { A = x });

            foreach (var item in list)
            {
                item.A = "bar";
            }

            foreach (var item in list)
            {
                Console.WriteLine(item.A);
            }
        }
    }

打印:

foo
foo

设置 item.A = "bar" 时究竟发生了什么?

在第一个 foreach 循环完成后,list var 是否真的包含相同的两个 Foo 对象并将 "bar" 作为新字符串?

如果是这样,您如何访问这些新值?

我知道当第二个 foreach 循环 运行s 时,它正在枚举字符串集合,这就是为什么你得到两个 "foo" 的打印输出,但我只是对当 item.A = "bar" 为 运行 时会发生什么,如果您永远无法访问该新值,为什么编译器允许您修改它?

问题是您没有调用 ToList 方法来实现您的 LINQ 查询。当您按如下方式调用 ToList 时:

var list = strings.Select(x => new Foo { A = x })
                  .ToList();

将创建 Foo 个对象的内存集合,其 属性 值 A 的值为 x。本质上,将创建两个 Foo 类型的新对象,A 的值为 "foo"。然后你可以遍历这个列表并修改 属性 值。

请看这个fiddle

你是对的,如果不会被改变,那么为什么编译器允许。但如果您想在这种情况下打印而不更新实际项目,上面的代码会有所帮助。

有一件事你应该知道,你不能修改 IEnumerable 对象的项目。 你必须使用 List();

 var strings = new List<string> { "foo", "foo" };
 var list = strings.Select(x => new Foo { A = x }).ToList();

    foreach (var item in list)
    {
            item.A = "bar";
    }

    foreach (var item in list)
    {
           Console.WriteLine(item.A);
    }

这里发生的事情是您正在创建一个可枚举的 list,您正在枚举多次。

每次枚举list,枚举处理strings列表的元素,为每个元素调用new Foo { A = x }创建结果序列的元素。

这意味着第一个 foreach 枚举创建的 Foo 对象与第二个 foreach 枚举创建的对象不同。为每个枚举创建新的。

这就是 Resharper 警告 "possible multiple enumeration" 的原因。

为避免这种情况,您可以使用 var list = strings.Select(x => new Foo { A = x }).ToList(); 仅枚举序列一次并将结果存储在实际的 List<T>.