簡體   English   中英

.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 查詢。

在這兩種情況下,數據中的對象都是 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM