C#中LINQ Where筛选后两种foreach写法的性能差异咨询
结论
这两种写法不存在任何可感知的执行性能差异,不存在谁比谁更快的说法。
原理解释
- 首先搞清楚LINQ里
Where()的执行特性:它是典型的延迟执行方法,调用时根本不会立刻遍历原集合做筛选,只会返回一个封装了筛选逻辑的迭代器对象,这个操作的开销极小,而且不管你是直接把Where()写在foreach括号里,还是先赋值给变量,这个步骤都只会执行1次。 foreach本身是C#的语法糖,它的执行逻辑是:循环启动前只获取一次迭代器,之后每轮循环靠迭代器的MoveNext()方法逐个取出符合条件的元素。两种写法的筛选执行时机、委托调用次数、内存分配行为完全一致,没有任何区别。- 你可以把两种写法编译后看IL代码,会发现二者生成的中间代码几乎一模一样,JIT编译器甚至会直接把这种只用一次的短生命周期局部变量优化掉,最终跑起来的机器码完全等价。
- 这里提一个常见误区:很多人以为直接写在foreach里的
Where()会每轮循环都重新执行一遍筛选,这是完全没搞懂foreach执行逻辑和LINQ延迟执行特性的错误认知,实际根本不会出现这种情况。
真正会产生性能差异的类似写法
只有你给Where()的结果追加了立刻执行的转换方法时,才会和直接遍历迭代器的写法产生性能差,比如:
// 这种写法才会有额外开销:ToList()会立刻执行全量筛选,把所有匹配项拷贝到新的List集合里 var myList = listValues.Where(x => x.Valid == false).ToList(); foreach (var obj in myList) { }
这种写法会多产生一次新集合的内存分配、一次全量遍历的开销,和你题目里给出的“仅存储Where返回的IEnumerable再遍历”的写法完全不是一回事。
选型建议
选哪种写法完全从可读性角度考虑就行:
- 筛选逻辑短的话,直接写在foreach里更简洁
- 筛选逻辑复杂,或者想给筛选结果起个语义明确的名字(比如
invalidConfigItems),抽成局部变量的写法可维护性更好,完全不需要为了所谓的性能纠结。
内容的提问来源于stack exchange,提问作者Ob Ahmed
相关产品推荐
相关产品推荐

