【问题标题】:Why does IQueryable implement IEnumerable? [closed]为什么 IQueryable 实现了 IEnumerable? [关闭]
【发布时间】:2015-03-18 15:10:55
【问题描述】:

我理解为什么IQueryableIEnumerable exist,但我不清楚从IQueryable 派生的IEnumerable 有什么好处。

我遇到的一个缺点:

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

     Users.DistinctBy(u => u.Address).Where(u => u.Age >= 18)
    

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

IQueryable 的工作方式,内部 Expression 被链式语句改变,似乎与链式函数的正常工作方式完全不同。

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

【问题讨论】:

  • 从这个 API 设计引起的 Stack Overflow 问题的数量来看,我会说你是对的。
  • 如果您想知道为什么 MS 做出了他们所做的决定,那么您需要询问他们,而不是让我们猜测他们做出决定的原因他们确实做到了,因为这根本没有成效,也不是一个客观可以回答的问题。
  • @Servy 这里有各种各样的 MS 程序员/前 MS 程序员,而且这些问题经常被提供知识:-)
  • @xanatos 然而,在成千上万曾经做过 MS 程序员的人中,只有少数人参与了这个决定。这里有全世界只有少数人能回答的问题,而且他们读到这些问题的几率微乎其微,对这里的每个人来说都不是有效的。
  • @MichaelParker 编辑后,问题比以前更加基于意见/主观。

标签: c# linq ienumerable iqueryable


【解决方案1】:

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

效果很好

这是 .NET 中集合的 leitmotif。如果您想在 List<> 集合上执行 Contains(执行 O(n) 操作),则没有安全网。如果您多次重新执行相同的查询,则没有安全网,因为您不知道IQueryableIEnumerable 之间的区别(请注意,即使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 兼容)。所以你用的是像螺丝一样的锤子,你抱怨它不是正确的工具:-)

微软给出的不产生集合的扩展方法通常是IQueryable-safe(除了Expression vs Func

出于好奇,MSDN的官方原因是:

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

And

此接口继承了 IEnumerable 接口,因此如果它表示一个查询,则可以枚举该查询的结果。枚举强制执行与 IQueryable 对象关联的表达式树。调用 Execute(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 :-) )
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-15
    • 2018-09-05
    • 2020-05-18
    • 1970-01-01
    • 2010-11-12
    • 2012-09-27
    • 2011-07-29
    • 2012-06-24
    相关资源
    最近更新 更多