Lambda表达式被执行两次:此问题是Visual Studio还是.NET运行时Bug?
这不是Bug,是LINQ延迟执行的特性导致的
你遇到的现象完全是LINQ延迟执行的预期行为,和Visual Studio或.NET运行时的Bug无关,具体拆解如下:
核心原因:LINQ查询的延迟执行
像Where这类LINQ方法返回的是一个查询对象,而不是立即计算出的结果集合。只有当你调用Count()、Max()、ToList()、Foreach()这类需要枚举结果的方法时,才会真正遍历原集合、执行Lambda表达式中的筛选/计算逻辑。
你的代码流程分析
- 第一次循环中,
Import方法把列表最后一项(Name="12")的IsImported设为true。 - 执行
temp = items.Where(p => p.Name.Length < maxLength && !p.IsImported)时,maxLength此时的值是2,这行代码只是创建了一个查询规则,并没有立即执行筛选。 - 接下来执行
maxLength = temp.Count() > 0 ? temp.Max(p => p.Name.Length) : 0:- 调用
temp.Count()时,会触发查询执行:用当前maxLength=2的条件筛选,得到符合条件的项(Name="1",未被导入),所以Count()返回1。 - 接着调用
temp.Max(...),会再次触发查询执行,还是用maxLength=2的条件筛选,计算出最大长度是1,随后maxLength被更新为1。 - 调试时看到VS进入上方的Lambda表达式体,就是因为
Count()和Max()触发了查询执行,这是正常的调试现象。
- 调用
- 为什么调试时看
temp“看似为空”?
当你在调试器中查看temp时,此时maxLength已经被更新为1了,调试器会重新执行查询,条件变成p.Name.Length <1 && !p.IsImported,自然没有符合条件的项。但实际上在Count()和Max()执行时,用的是更新前的maxLength=2,所以当时的查询是有效的。
为什么加ToList()就正常?
ToList()会立即执行查询,把筛选结果缓存到一个新的List<Entity>中,后续操作的是这个缓存的集合,不再受maxLength变量变化的影响,所以调试和运行结果都会符合预期。
内容的提问来源于stack exchange,提问作者bit
相关产品推荐
相关产品推荐

