您如何知道一个集合将充当 IEnumerable 还是 IQueryable?
How do you know if a collection will act as IEnumerable or IQueryable?
我有这行代码:
var attachments = EntityRepository<Attachment>().Entities
.Where(at => at.EntityType == EntityType.EmailTemplate)
.ToDictionary(at => at.Extension, at => at);
EntityRepository<Attachment>().Entities
是 System.Data.Entity.Infrastructure.DbQuery<TResult>
类型,它实现了 IQueryable<TResult>
和 IEnumerable<TResult>
。
如果它作为 IEnumerable<T>
(即从数据库中检索所有行,然后在 C# 中进行过滤)或作为 IQueryable<T>
(转换C# 谓词到 SQL 查询并仅检索那些行)。
我想你可能对IEnumerable
有点误解。它只是说 class 支持迭代。它不会直接影响任何数据的获取方式。
此外,IQueryable
实现了 IEnumerable
,因此所有 IQueryable
实例也是 IEnumerable
。这是有道理的,因为您可以迭代结果。
在您的示例中,缺少 IQueryable
意味着 "retrieve all rows from DB, then do the filtering in C#"。
LINQ 中有 2 个不同的扩展 - IEnumerable and for IQueryable。
当你写 EntityRepository<Attachment>().Entities
.Where(at => at.EntityType == EntityType.EmailTemplate)
时,编译器检查 Entities
的类型,当它声明 'more specific' IQueryable
时,编译器选择 Queryable.Where()
方法,表达式被翻译成IQueryProvider 到 SQL。当您编写 .ToDictionary(at => at.Extension, at => at)
时,编译器找不到 Queryable.ToDictionary()
,因此它回退到 Enumerable.ToDictionary()
并在内存中过滤项目。
扩展方法调用规则定义在C# language spec:
- The set of candidate methods is reduced to contain only methods from the most derived types: For each method
C.F
in the set, where C
is the type in which the method F
is declared, all methods declared in a base type of C
are removed from the set. Furthermore, if C
is a class type other than object
, all methods declared in an interface type are removed from the set. (This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)
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
}
}
我有这行代码:
var attachments = EntityRepository<Attachment>().Entities
.Where(at => at.EntityType == EntityType.EmailTemplate)
.ToDictionary(at => at.Extension, at => at);
EntityRepository<Attachment>().Entities
是 System.Data.Entity.Infrastructure.DbQuery<TResult>
类型,它实现了 IQueryable<TResult>
和 IEnumerable<TResult>
。
如果它作为 IEnumerable<T>
(即从数据库中检索所有行,然后在 C# 中进行过滤)或作为 IQueryable<T>
(转换C# 谓词到 SQL 查询并仅检索那些行)。
我想你可能对IEnumerable
有点误解。它只是说 class 支持迭代。它不会直接影响任何数据的获取方式。
此外,IQueryable
实现了 IEnumerable
,因此所有 IQueryable
实例也是 IEnumerable
。这是有道理的,因为您可以迭代结果。
在您的示例中,缺少 IQueryable
意味着 "retrieve all rows from DB, then do the filtering in C#"。
LINQ 中有 2 个不同的扩展 - IEnumerable and for IQueryable。
当你写 EntityRepository<Attachment>().Entities
.Where(at => at.EntityType == EntityType.EmailTemplate)
时,编译器检查 Entities
的类型,当它声明 'more specific' IQueryable
时,编译器选择 Queryable.Where()
方法,表达式被翻译成IQueryProvider 到 SQL。当您编写 .ToDictionary(at => at.Extension, at => at)
时,编译器找不到 Queryable.ToDictionary()
,因此它回退到 Enumerable.ToDictionary()
并在内存中过滤项目。
扩展方法调用规则定义在C# language spec:
- The set of candidate methods is reduced to contain only methods from the most derived types: For each method
C.F
in the set, whereC
is the type in which the methodF
is declared, all methods declared in a base type ofC
are removed from the set. Furthermore, ifC
is a class type other thanobject
, all methods declared in an interface type are removed from the set. (This latter rule only has affect when the method group was the result of a member lookup on a type parameter having an effective base class other than object and a non-empty effective interface set.)
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
}
}