我维护的代码有一个像下面这样的常见模式,一个嵌套循环,用 if 来查找某些元素。
foreach (Storage storage in mStorage.Values)
foreach (OrderStorage oStorage in storage.OrderStorage)
if (oStorage.OrderStorageId == orderStorageId)
我想把它改成 LINQ:
foreach (OrderStorage oStorage in (from storage in mStorage.Values
from oStorage in storage.OrderStorage
where oStorage.OrderStorageId == orderStorageId
select oStorage))
但这似乎并没有那么吸引人,因为这里发生的事情不太透明,可能会创建更多的对象,从而在内存和 CPU 方面造成性能损失。实际上是否会创建更多对象,或者 C# 编译器是否会发出类似于嵌套循环的代码?
最佳答案
更多对象;每个 LINQ 操作( SelectMany
、 Where
、 Select
等)将产生一个新的占位符对象,表示该操作的待处理 IEnumerable<T>
查询,然后当它最终被迭代时,每个操作都会产生一个枚举器实例,以及上下文等。另外还有一个用于提升的 orderStorageId
等的捕获变量上下文。
请注意,常规 foreach
也会产生枚举器实例,但 foreach
的优点是它也可以使用鸭子类型的枚举器——这意味着对于 List<T>
之类的东西,它实际上使用的是 struct
枚举器,而不是 class
枚举器。当然,直接使用局部变量( orderStorageId
)(而不是匿名方法)意味着它不需要被提升到状态/上下文对象中。
所以是的,原始的 foreach
更加直接和高效。有趣的问题是:差异是否重要。有时是,有时不是。