LINQ 方法和 IEnumerableT 與 IQueryableT

關於 IEnumerable<T> 的 LINQ 擴充套件方法採用實際方法 1 ,是否匿名方法:

//C#
Func<int,bool> fn = x => x > 3;
var list = new List<int>() {1,2,3,4,5,6};
var query = list.Where(fn);

'VB.NET
Dim fn = Function(x As Integer) x > 3
Dim list = New List From {1,2,3,4,5,6};
Dim query = list.Where(fn);

或命名方法(明確定義為類的一部分的方法):

//C#
class Program {
    bool LessThan4(int x) {
        return x < 4;
    }

    void Main() {
        var list = new List<int>() {1,2,3,4,5,6};
        var query = list.Where(LessThan4);
    }
}

'VB.NET
Class Program
    Function LessThan4(x As Integer) As Boolean
        Return x < 4
    End Function
    Sub Main
        Dim list = New List From {1,2,3,4,5,6};
        Dim query = list.Where(AddressOf LessThan4)
    End Sub
End Class

從理論上講,可以解析方法的 IL ,弄清楚方法嘗試做什麼,並將該方法的邏輯應用於任何底層資料來源,而不僅僅是記憶體中的物件。但解析 IL 不適合膽小的人。

幸運的是,.NET 提供了 IQueryable<T> 介面,以及 System.Linq.Queryable 的擴充套件方法。這些擴充套件方法採用表示式樹 - 表示程式碼的資料結構 - 而不是實際方法,然後 LINQ 提供程式可以解析 2 並轉換為更合適的形式以查詢底層資料來源。例如:

//C#
IQueryable<Person> qry = PersonsSet();

// Since we're using a variable of type Expression<Func<Person,bool>>, the compiler 
// generates an expression tree representing this code
Expression<Func<Person,bool>> expr = x => x.LastName.StartsWith("A");
// The same thing happens when we write the lambda expression directly in the call to 
// Queryable.Where

qry = qry.Where(expr);

'VB.NET
Dim qry As IQueryable(Of Person) = PersonSet()

' Since we're using a variable of type Expression(Of Func(Of Person,Boolean)), the compiler 
' generates an expression tree representing this code
Dim expr As Expression(Of Func(Of Person, Boolean)) = Function(x) x.LastName.StartsWith("A")
' The same thing happens when we write the lambda expression directly in the call to 
' Queryable.Where

qry = qry.Where(expr)

如果(例如)此查詢針對 SQL 資料庫,則提供程式可以將此表示式轉換為以下 SQL 語句:

SELECT *
FROM Persons
WHERE LastName LIKE N'A%'

並針對資料來源執行它。

另一方面,如果查詢針對 REST API,則提供程式可以將同一表示式轉換為 API 呼叫:

http://www.example.com/person?filtervalue=A&filtertype=startswith&fieldname=lastname

基於表示式定製資料請求有兩個主要好處(而不是將整個集合載入到記憶體中並在本地查詢):

  • 底層資料來源通常可以更有效地查詢。例如,LastName 上可能有一個索引。將物件載入到本地記憶體並查詢記憶體會失去效率。
  • 資料可以在傳輸之前進行整形和縮小。在這種情況下,資料庫/ Web 服務只需要返回匹配的資料,而不是從資料來源中獲得的整個人員集。

註釋
1.從技術上講,它們實際上並不採用方法,而是委託指向方法的例項 。但是,這種區別在這裡無關緊要。
2.這就是 “ LINQ to Entities 無法識別方法’System.String ToString()‘方法 錯誤的原因*,並且此方法無法轉換為商店表示式。* ” LINQ 提供程式(在本例中為 Entity Framework 提供程式)不知道如何解析和轉換對 ToString 的呼叫到等效的 SQL。 **