为什么 IQueryable 实现 IEnumerable?

Mic*_*ker 4 c# linq ienumerable iqueryable

我明白为什么IQueryableIEnumerable exist,但我不清楚从IQueryable中获得什么好处IEnumerable

我遇到的缺点之一:

  • 任何创建自己的IEnumerable扩展方法的人都可能很容易意外地将看似无辜的IQueryable查询转换为低效的IEnumerable调用。例如,使用 MoreLinq:

     Users.DistinctBy(u => u.Address).Where(u => u.Age >= 18)
    
    Run Code Online (Sandbox Code Playgroud)

(这将使用IEnumerable.Where而不是IQueryable.Where除非我错过了IQueryable上述的实现)

其工作方式(通过链式语句更改的IQueryable内部)似乎与链式函数通常预期的工作方式截然不同。Expression

我怀疑这个接口继承有一些强大的优点,但我可能没有充分利用这些优点。与执行查询的显式转换相比,IQueryable实现有什么好处?IEnumerable

xan*_*tos 5

(我确实IQueryable认为继承自是愚蠢的IEnumerable)...但是!

它就是有效的

这是.NET 中集合的主题Contains如果您想对集合执行操作List<>(执行 O(n) 操作),则没有安全网。如果您多次重新执行相同的查询,则没有安全网,因为您不知道IQueryable和之间的区别IEnumerable(并且请注意,即使IEnumerable不能保证结果的缓存:-))。

由于这种继承,所有接受IEnumerable/的方法都IEnumerable<T>接受IQueryable//IQueryable<T>IOrderedQueryable<T>

它就是有效的

大量的 VB 程序员对 Variant 数据类型感到满意...大量的 .NET 程序员会对缓慢的查询感到满意:-)

一如既往,有卓越的空间,也有草率编程的空间。任何人都有空间:-)

我要补充一点,您给出的示例来自外部库,并带有说明LINQ to Objects is missing a few desirable features. (请注意,DistinctBy可以使用GroupBy+ “模拟” Select(First()),因此可以将其构建为与 IQueryable 兼容)。所以你像使用螺丝一样使用锤子,并且抱怨这不是正确的工具:-)

Microsoft 提供的不生成集合的扩展方法通常是IQueryable安全的(除了Expressionvs Func

出于好奇,MSDN官方给出的理由是:

IQueryable 接口继承了 IEnumerable 接口,因此如果它表示一个查询,则可以枚举该查询的结果。枚举会导致执行与 IQueryable 对象关联的表达式树。

该接口继承了 IEnumerable<T> 接口,因此如果它表示一个查询,则可以枚举该查询的结果。枚举强制执行与 IQueryable<T> 对象关联的表达式树。调用 Execute<TResult>(Expression) 方法时,将执行不返回可枚举结果的查询。

可悲的是(至少对我来说),这不是一个足够好的理由,因为他们本可以

  • 只需让其AsEnumerable()以明确的方式完成工作

或者

  • 在(和相关的)接口中放入IQueryable一个方法GetEnumerator(),因为foreach使用鸭子类型,它会很高兴。

例如:

public interface IMyEnumerabe<T>
{
    IEnumerator<T> GetEnumerator();
}

IMyEnumerabe<int> myenumerable = null;

foreach (int el in myenumerable)
{
    // Compiles (and in this cases crashes with a NullReferenceException :-) )
}
Run Code Online (Sandbox Code Playgroud)