.Take() 的行为如何根据我在左侧使用的接口参考而变化。 IQueryable 与 IEnumerable
How does the behavior of .Take() changes based on the interface reference I'm using on left. IQueryable vs IEnumerable
假设我有这些示例代码
IQueryable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy");
var topEmp = data.Take(1);
foreach (var item in topEmp)
{
Console.WriteLine(item.FullName);
}
和
IEnumerable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy");
var topEmp = data.Take(1);
foreach (var item in topEmp)
{
Console.WriteLine(item.FullName);
}
它们之间的唯一区别是我使用的是 IQueryable 与 IEnumerable 的引用。
第一个片段正在生成 sql 查询以获取与过滤条件匹配的前 1 项,而后一个片段正在生成没有顶部过滤器的 sql 查询。
在这两种情况下,data 中的对象都是类型
Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable
但是第一个场景中的 topEmp 是类型:Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable
和
第二个是 System.Linq.Enumerable.EnumerablePartition
.Take 方法的行为如何根据左侧的接口引用而改变。我看到“数据”变量在这两种情况下都是相同的类型。根据我的理解,如果左侧引用是 class 那么 .Take of that class 可以被调用;但它们是接口。我确定我在这里遗漏了 C# 的基本概念。
你是对的,你错过了 C# 的一个基本概念,这个概念是扩展方法。
我们没有调用 Enumerable
对象实现的抽象 Take
方法。
相反,我们正在调用一个独立于对象存在的函数:Take
扩展方法。根据对象的类型有不同的方法。
在 System.Core 库中存在这些静态 类.
public static class Queryable
{
public static IQueryable<TSource> Take<TSource>(
this IQueryable<TSource> source,
int count
);
// Many other methods...
}
public static class Enumerable
{
public static IEnumerable<TSource> Take<TSource>(
this IEnumerable<TSource> source,
int count
);
// Many other methods...
}
扩展方法在编译时解析,而不是运行时。
您的 data
变量恰好实现了 IQueryable<T>
。但是,一旦您将其转换为 IEnumerable<T>
,编译器必须选择 IEnumerable<T>
扩展方法。
您没有调用相同的 .Take()
方法。
Enumerable.Take
returns 一个新的 IEnumerable
将枚举枚举中的项目并生成它们。
Queryable.Take
returns 一个新的 IQueryable
,代表一棵 Expression
树。当您开始枚举该可查询时,该表达式将被编译为 SQL.
假设我有这些示例代码
IQueryable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy");
var topEmp = data.Take(1);
foreach (var item in topEmp)
{
Console.WriteLine(item.FullName);
}
和
IEnumerable<Employee> data = context.Employees.Where(x => x.FullName != "Shekar Reddy");
var topEmp = data.Take(1);
foreach (var item in topEmp)
{
Console.WriteLine(item.FullName);
}
它们之间的唯一区别是我使用的是 IQueryable 与 IEnumerable 的引用。 第一个片段正在生成 sql 查询以获取与过滤条件匹配的前 1 项,而后一个片段正在生成没有顶部过滤器的 sql 查询。
在这两种情况下,data 中的对象都是类型 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 但是第一个场景中的 topEmp 是类型:Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 和 第二个是 System.Linq.Enumerable.EnumerablePartition
.Take 方法的行为如何根据左侧的接口引用而改变。我看到“数据”变量在这两种情况下都是相同的类型。根据我的理解,如果左侧引用是 class 那么 .Take of that class 可以被调用;但它们是接口。我确定我在这里遗漏了 C# 的基本概念。
你是对的,你错过了 C# 的一个基本概念,这个概念是扩展方法。
我们没有调用 Enumerable
对象实现的抽象 Take
方法。
相反,我们正在调用一个独立于对象存在的函数:Take
扩展方法。根据对象的类型有不同的方法。
在 System.Core 库中存在这些静态 类.
public static class Queryable
{
public static IQueryable<TSource> Take<TSource>(
this IQueryable<TSource> source,
int count
);
// Many other methods...
}
public static class Enumerable
{
public static IEnumerable<TSource> Take<TSource>(
this IEnumerable<TSource> source,
int count
);
// Many other methods...
}
扩展方法在编译时解析,而不是运行时。
您的 data
变量恰好实现了 IQueryable<T>
。但是,一旦您将其转换为 IEnumerable<T>
,编译器必须选择 IEnumerable<T>
扩展方法。
您没有调用相同的 .Take()
方法。
Enumerable.Take
returns 一个新的 IEnumerable
将枚举枚举中的项目并生成它们。
Queryable.Take
returns 一个新的 IQueryable
,代表一棵 Expression
树。当您开始枚举该可查询时,该表达式将被编译为 SQL.