LINQ与嵌套循环比较

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
如果你有两匹马,想知道哪一匹跑得更快,那就 让它们比赛 - It'sNotALie.
1个回答

14
实际上会创建更多的对象,C#编译器生成类似于if内嵌循环的代码。
每个LINQ操作(如SelectManyWhereSelect等)都会产生一个新的占位符对象,表示该操作的待处理IEnumerable<T>查询,当最终进行迭代时,每个对象都会生成一个枚举器实例,以及相关的上下文等。此外,对于被提升的orderStorageId等变量,还有一个捕获变量的上下文。
请注意,常规的foreach也将生成一个枚举器实例,但foreach的优点在于它还可以使用鸭子类型的枚举器-这意味着对于像List<T>这样的东西,它实际上正在使用一个结构体枚举器,而不是一个类枚举器。当然,直接使用局部变量(orderStorageId)而不是在匿名方法中使用,意味着它不需要被提升到状态/上下文对象中。
因此,是的,原始的foreach更直接和高效。有趣的问题是:差异是否重要。有时候是,有时候不是。

1
同意@marcgravell的观点,使用LINQ会带来性能损失,但它可以提高可维护性和并行处理的便利性。性能与可维护性之间的权衡是计算机编程艺术的体现。 - Jim Wooley

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接