我正在考虑linq计算的方式,这让我想知道:
如果我写
var count = collection.Count(o => o.Category == 3);
这与以下内容有何不同:
var count = collection.Where(o => o.Category == 3).Count();
毕竟,IEnumerable<T>.Where()
将返回IEnumerable<T>
未实现Count
属性的内容,因此后续的Count()
实际上必须遍历项目以确定计数这会导致额外的时间花在这上面。
我写了一些快速测试代码来获得一些指标,但它们似乎随机相互击败。我最初不会在这里输入测试代码,但如果有人要求,我会把它拿进来。
那么,我错过了什么吗?
答案 0 :(得分:3)
其中不会有很多,真的 - 两种形式都会迭代集合,检查每个项目的谓词,并计算匹配。这两种方法都会对数据进行流式传输 - 例如,Where
实际上并不是在构建所有匹配项的内存列表。
第一种形式有一个(薄)间接层,这就是全部。使用它(IMO)的主要原因是为了可读性/简单性,而不是性能。
答案 1 :(得分:2)
正如Jon Skeet所说,两种技术都必须基本上做同样的事情 - 在谓词匹配时有条件地递增计数器时枚举序列。两者之间的任何性能差异都应该是轻微的:对于几乎所有用例来说都是微不足道的。如果有令牌获胜者,我会认为它应该是第一个,因为从反射器看来,带有谓词的Count
的重载使用了它自己的{{1}如第二个示例所示,枚举而不是将工作卸载到foreach
到无参数 Where
的更明显的方式。这意味着技术#1 可能具有两个次要性能优势:
Count
还会检查其(管道)输入是Count
还是ICollection
,这是不可能的。虽然有一个未成年人赞成技术#2点:ICollection<T>
在为源序列构造枚举器时稍微复杂一些;它对列表和数组使用不同的一个。 可能在某些情况下使其更具性能。
当然,我应该重申,我可能对我的分析很明显错误 - 通过静态代码分析来推断性能,特别是当差异可能很小时,这不是一个好主意。只有一种方法可以找到 - 测量特定设置的执行时间。
仅供参考,我反映的来源是.NET 3.5 SP1。
答案 2 :(得分:0)
我知道你在想什么。至少,我想我做; Count()
会查看Count
是否可用作属性,如果是,则会返回。否则,它必须枚举项以获得其返回值。
接受谓词的Count()
版本总是会导致集合被迭代,因为它必须这样做以查看哪些匹配。
答案 3 :(得分:0)
上面的答案提出了好的观点,还要考虑如果你闯入延迟执行的任何Linq-To-X实现(Linq到Sql是主要的),这些方法中使用的Expression参数可能会导致不同的结果。