[英]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 查詢。
在這兩種情況下,數據中的對象都是 Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable 類型,但是第一個場景中的 topEmp 是類型:Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable,第二個是 System.Linq .Enumerable.EnumerablePartition
.Take 方法的行為如何根據左側的接口引用發生變化。 我看到“數據”變量在兩種情況下都是相同的類型。 根據我的理解,如果左側引用是一個類,則可以調用該類的 .Take ; 但它們是接口。 我確定我在這里遺漏了 C# 的基本概念。
您沒有調用相同的.Take()
方法。
Enumerable.Take
返回一個新的IEnumerable
,它將枚舉枚舉中的項目並產生它們。
Queryable.Take
返回一個新的IQuerable
,以表示Expression
樹。 當您開始枚舉該可查詢對象時,該表達式將被編譯為 sql。
您錯過了 C# 的一個基本概念是正確的,這個概念是extension methods 。
我們不是調用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>
擴展方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.