C# 选择后的foreach迭代
有人能解释这种行为吗C# 选择后的foreach迭代,c#,linq,C#,Linq,有人能解释这种行为吗 class Program { static void Main(string[] args) { var models = Enumerable.Range(0, 10).Select(x => new Model { Id = x.ToString() }); foreach (var model in models) { model.Data = $"{model.Id}
class Program
{
static void Main(string[] args)
{
var models = Enumerable.Range(0, 10).Select(x => new Model { Id = x.ToString() });
foreach (var model in models)
{
model.Data = $"{model.Id} Data bla";
}
foreach (var model in models)
{
Console.WriteLine($"{model.Id} | {model.Data}");
}
Console.ReadLine();
}
}
public class Model
{
public string Id { get; set; }
public string Data { get; set; }
}
输出:
0|
一,|
二,|
但是,如果在选择之后调用ToList(),则输出将更改为:
0 | 0数据bla
1 | 1数据bla
2 | 2数据bla
我尝试在每个foreach块中放置一个断点,并调用
models.Any(x=>x.Equals(model))
但是总是返回false,而不使用ToList()调用
models
是一个序列,每次迭代时都会填充Model
的新实例。也就是说,你每次都会得到一组新的实例
当您调用
ToList()
时,您将捕获一个迭代的副本和所有可以修改的实例 .Select()
在枚举之前不会具体化其结果。第一个foreach
更改一组newmodel{}
对象,第二个foreach
处理一组全新的newmodel{}
对象。.ToList()
将它一劳永逸地具体化。但是foreach块本身不是通过模型枚举的吗?当然是这样——但是每个块都通过自己的一组模型枚举。第一个foreach
也可能没有发生,因为结果从未被使用过。@StefanKovacs:如果没有ToList
它就像你用Enumerable.Range(0,10)替换模型的每个实例一样。选择(x=>新模型{Id=x.ToString()})
,因为Select不会生成项目,它只提供允许生成它们的代码。当您迭代模型时,它每次都运行该代码来生成项目。实际上,我在模型对象中添加了一个新字段:publicstringguid=System.Guid.NewGuid().ToString()代码>并使用model.Id和model.Guid执行Console.WriteLine。第一个foreach中的模型与第二个foreach中的模型具有不同的guid谢谢@StefanKovacs仅供参考-您还可以查看.GetHashCode()
,这是检查其是否为同一对象的更常见方法