4

我维护的代码有一个像下面这样的通用模式,一个带有 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# 编译器是否会发出类似于嵌套循环的代码,其中包含 if ?

4

1 回答 1

14

实际上是否会创建更多对象,或者 C# 编译器是否会发出类似于嵌套循环的代码,其中包含 if ?

更多对象;每个 LINQ 操作 ( SelectMany,WhereSelect) 将产生一个新的占位符对象,该对象表示该IEnumerable<T>操作的待处理查询,然后当它最终迭代时,每一个都将产生一个枚举器实例以及上下文等。另外还有一个被提升的变量上下文orderStorageId等。

请注意,常规foreach也会产生一个枚举器实例,但foreach它的优点是它也可以使用鸭子类型的枚举器——这意味着List<T>它实际上是在使用struct枚举器,而不是class枚举器。当然使用局部变量(orderStorageId直接使用局部变量 ( )(而不是在匿名方法中)意味着它不需要被提升到状态/上下文对象中。

所以是的,原始foreach的更直接和有效。有趣的问题是:差异是否重要。有时是,有时不是。

于 2013-08-09T11:20:58.730 回答