C# LINQ:筛选任务并理解延迟执行时机
用 LINQ 筛选任务并求和,通过修改源集合观察延迟查询与 ToArray 快照的区别,明确结果在什么时候计算。
本节目标
用 LINQ 筛选任务并求和,通过修改源集合观察延迟查询与 ToArray 快照的区别,明确结果在什么时候计算。
环境与运行方法
准备 .NET 8 SDK,创建目录后执行 dotnet new console --framework net8.0。用示例替换 Program.cs,执行 dotnet run。这里使用顶层语句,不要再套入另一份 Main。
核心思路
Where 通常返回延迟查询,定义查询不等于已经把结果保存下来。ToArray 会立即枚举并生成数组。本例分别保存查询与快照,再修改源列表,观察两者计数不同。
完整示例
var minutes = new List<int> { 20, -5, 35 };
var query = minutes.Where(value => value >= 0);
var snapshot = query.ToArray();
minutes.Add(10);
Console.WriteLine("query=" + query.Count());
Console.WriteLine("snapshot=" + snapshot.Length);
Console.WriteLine("total=" + query.Sum());预期输出
query=3
snapshot=2
total=65逐步理解
创建 query 时并未完成筛选。snapshot 在 Add 前计算,所以保存 20 与 35;后续 Count 枚举 query 时会看到新加入的 10。Sum 又执行一次枚举,得到 65。
如果数据来源昂贵或会变化,重复枚举可能影响性能或结果一致性。需要稳定多次使用时可物化一次,再围绕快照计算;但快照只复制元素值或引用,不保证深层对象不可变。不要把延迟执行误解成自动并行。
常见问题与边界
- 查询定义处与执行处可能相隔很远。
- 在枚举期间修改 List 可能触发异常。
- ToArray 对引用类型元素不等于深拷贝。
动手练习
把 Add(10) 改为 Add(-10),预测三个输出。
参考答案
查询计数仍为 2,快照长度仍为 2,总和为 55。新负值存在于原集合,但被查询条件排除。
文章回复
0 条公开回复