关于IEnumerable与List的C#foreach - 仅针对数组的元素修改 - 为什么?

And*_*son 3 c# ienumerable foreach reference

在C#中,我注意到如果我在LINQ生成的IEnumerable<T>集合上运行foreach循环并尝试修改每个T元素的内容,我的修改就不会持久.

另一方面,如果我在创建集合时应用ToArray()or ToList()方法,则对foreach循环各个元素的修改持久的.

我怀疑这在某种程度上与延迟执行有关,但究竟对我来说并不完全是显而易见的.我真的很感激这种行为差异的解释.

这是一些示例代码 - 我有一个MyClass带有构造函数和自动实现属性的类:

public class MyClass
{
    public MyClass(int val) { Str = val.ToString(); }
    public string Str { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

在我的示例应用程序中,我使用LINQ 基于一个整数Select()集合创建两个MyClass对象集合,一个IEnumerable<MyClass>和一个最后IList<MyClass>应用该ToList()方法.

var ints = Enumerable.Range(1, 10);
var myClassEnumerable = ints.Select(i => new MyClass(i));
var myClassArray = ints.Select(i => new MyClass(i)).ToList();
Run Code Online (Sandbox Code Playgroud)

接下来,我在每个集合上运行一个foreach循环,并修改循环MyClass对象的内容:

foreach (var obj in myClassEnumerable) obj.Str = "Something";
foreach (var obj in myClassArray) obj.Str = "Something else";
Run Code Online (Sandbox Code Playgroud)

最后,我输出Str每个集合中第一个元素的成员:

Console.WriteLine(myClassEnumerable.First().Str);
Console.WriteLine(myClassArray.First().Str);
Run Code Online (Sandbox Code Playgroud)

有点违反直觉,输出是:

1
Something else
Run Code Online (Sandbox Code Playgroud)

Wou*_*ort 13

延期执行确实是关键点.

执行myClassEnumerable.First().Str将重新执行您的查询ints.Select(i => new MyClass(i));,因此它将为您提供一个新的IEnumerable,其中包含一个新的整数列表.

您可以使用调试器查看此操作.new MyClass(i)在IEnumerable select 的一部分放置一个断点,当你为Console.WriteLine执行它时,你会看到这个部分再次被击中