【问题标题】:How do you know if a collection will act as IEnumerable or IQueryable?你怎么知道一个集合是充当 IEnumerable 还是 IQueryable?
【发布时间】:2019-12-14 13:28:11
【问题描述】:

我有这行代码:

var attachments = EntityRepository<Attachment>().Entities
.Where(at => at.EntityType == EntityType.EmailTemplate)
.ToDictionary(at => at.Extension, at => at);

EntityRepository&lt;Attachment&gt;().EntitiesSystem.Data.Entity.Infrastructure.DbQuery&lt;TResult&gt; 类型,它同时实现了 IQueryable&lt;TResult&gt;IEnumerable&lt;TResult&gt;

我如何确定它是充当IEnumerable&lt;T&gt;(即从数据库中检索所有行,然后在C# 中进行过滤),还是充当IQueryable&lt;T&gt;(将C# 谓词转换为SQL 查询并仅检索那些行)。

【问题讨论】:

  • 您可以检查查询实例是否实现接口:myQuery is IQueryable。我感觉你可能会打XY problem,所以请详细说明你为什么要解决这个问题。
  • @IlliaPopov 这不是 XY 问题。代码工作正常。我只是好奇幕后发生了什么。

标签: c# entity-framework ienumerable iqueryable


【解决方案1】:

我想你可能对IEnumerable有一点误解。它只是说该类支持迭代。它不会直接影响任何数据的获取方式。

另外,IQueryable 实现了IEnumerable,所以所有IQueryable 实例也是IEnumerable。这是有道理的,因为您可以迭代结果。

在您的示例中,缺少IQueryable 意味着“从数据库中检索所有行,然后在 C# 中进行过滤”。

【讨论】:

  • 有道理,现在看起来很明显!谢谢你的回答。
【解决方案2】:

LINQ 中有 2 种不同的扩展 - IEnumerableIQueryable

当您编写EntityRepository<Attachment>().Entities .Where(at => at.EntityType == EntityType.EmailTemplate) 时,编译器检查Entities 的类型,并在声明“更具体”时IQueryable 编译器选择Queryable.Where() 方法,表达式由IQueryProvider 转换为SQL。当您编写.ToDictionary(at =&gt; at.Extension, at =&gt; at) 时,编译器找不到Queryable.ToDictionary(),因此它会退回到Enumerable.ToDictionary(),并且项目会在内存中过滤。

扩展方法调用的规则定义在C# language spec:

  • 候选方法集被缩减为仅包含来自最多派生类型的方法:对于集合中的每个方法C.F,其中C 是方法@987654334 所在的类型@ 被声明时,所有在 C 基类型中声明的方法都将从集合中删除。此外,如果Cobject 以外的类类型,则从集合中删除在接口类型中声明的所有方法。 (仅当方法组是对具有除 object 之外的有效基类和非空有效接口集的类型参数的成员查找结果时,后一条规则才有效。)
    public interface IInterfaceA { }
    public interface IInterfaceB : IInterfaceA { }

    public static class MyExtensions {
        public static void Print(this IInterfaceA a) => Console.WriteLine("A");
        public static void Print(this IInterfaceB b) => Console.WriteLine("B");
    }

    public class AB: IInterfaceA, IInterfaceB { }
    public class BA: IInterfaceB, IInterfaceA { }

    public partial class Program
    {
        static void Main(string[] args)
        {
            new AB().Print(); // B
            new BA().Print(); // B
        }
    }

【讨论】:

  • 感谢您表明实现接口的顺序并不重要,这是一个常见的误解。
猜你喜欢
  • 1970-01-01
  • 2011-11-28
  • 2021-12-13
  • 2010-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多