这取决于people 是什么。
如果people 是IEnumerable 对象(如集合,或使用yield 的方法的结果),那么您问题中的两段代码确实是等价的。
一个幼稚的Where 可以实现为:
public static IEnumerable<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
// Error handling left out for simplicity.
foreach (TSource item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
Enumerable 中的实际代码有点不同,以确保传递 null source 或 predicate 的错误立即发生而不是延迟执行,并针对少数情况进行优化(例如 @987654330 @ 变成了 source.Where(x => x.IsCriminal && x.IsOnParole) 的等价物,这样在迭代链中就少了一个步骤),但这是基本原则。
但是,如果 people 是 IQueryable,则情况有所不同,具体取决于相关查询提供程序的详细信息。
最简单的可能性是查询提供者不能对Where 做任何特殊的事情,所以它最终只能做上面的事情,因为这仍然有效。
但查询提供者通常可以做其他事情。假设people 是实体框架中的DbSet<Person>,与数据库中名为people 的表相关联。如果你这样做:
foreach(var person in people)
{
DoSomething(person);
}
然后 Entity Framework 将运行类似于以下的 SQL:
SELECT *
FROM people
然后为返回的每一行创建一个Person 对象。我们可以在即将实现Where 时进行相同的过滤,但我们还可以做得更好。
如果你这样做:
foreach (Person criminal in people.Where(person => person.isCriminal)
{
DoSomething(person);
}
然后 Entity Framework 将运行类似于以下的 SQL:
SELECT *
FROM people
WHERE isCriminal = 1
这意味着决定返回哪些元素的逻辑在返回到 .NET 之前在数据库中完成。它允许在计算WHERE 时使用索引,这可以提高效率,但即使在没有有用索引并且数据库必须进行全面扫描的更糟糕的情况下,它仍然意味着我们不使用的那些记录't care about 永远不会从数据库中报告回来,并且没有为它们创建的对象只是为了再次被丢弃,因此性能差异可能是巨大的。
我想从效率的角度了解更多
希望您对不会发生您所建议的双重通过感到满意,并且很高兴得知它比您尽可能建议的 foreach … if 更有效。
foreach 和 if 仍然会在 IEnumerable 上击败 .Where()(但不是在数据库源上),因为 Where 与 foreach 和 if 之间存在一些开销没有,但它的程度只有在非常热的道路上才值得关心。一般来说,Where 可以在对其效率有合理信心的情况下使用。