首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

釐清 LINQ 核心概念:Expression Tree、Lambda、Query Expression 與 Query Operator

     編輯:關於.NET

初學 LINQ 易混淆的五大術語:Expression Tree、Expression、Lambda Expression、Query Expression、Query Operator。本文逐一解析差異與關聯。

術語對照表

術語定義與角色
Expression Tree表示對 IQueryable<T> 查詢的樹狀結構,由多個 Query Method 巢狀組成,運行期由 LINQ to SQL 轉譯為 SQL
ExpressionSystem.Linq.Expressions.Expression 類別,運算式樹每個節點的基類,提供建構各類節點的 Factory Method
Lambda Expression可作為運算式樹節點(Expression<TDelegate>)或編譯為委托(Func<T>)的語法糖
Query OperatorEnumerable/Queryable 中定義的擴充方法(Where/Select/Join/OrderBy/GroupBy 等)
Query Expression類 SQL 語法(from/where/select),編譯器將其轉譯為 Query Operator 呼叫

手動構建 Expression Tree 範例

對應 context.Customers.Where(c => c.City == "London"):

ConstantExpression customersExpr = Expression.Constant(context.Customers);
ParameterExpression paramExpr = Expression.Parameter(typeof(Customer), "c");
MemberExpression cityExpr = Expression.Property(paramExpr, "City");
BinaryExpression equalExpr = Expression.Equal(cityExpr, Expression.Constant("London"));
LambdaExpression lambdaExpr = Expression.Lambda(equalExpr, paramExpr);
MethodCallExpression whereExpr = Expression.Call(
    typeof(Queryable), "Where", new Type[] { typeof(Customer) },
    customersExpr, lambdaExpr);
// 輸出:Table(Customer).Where(c => (c.City = "London"))

Expression.Quote() 用途

Quote(expr) 將運算式本身作為值輸出,而非運算結果:

BinaryExpression expr = Expression.Add(Expression.Constant(2), Expression.Constant(3));
var expr1 = Expression.Lambda<Func<int>>(expr);           // () => 2 + 3
var expr2 = Expression.Lambda<Func<BinaryExpression>>(Expression.Quote(expr)); // () => (2 + 3)
expr1.Compile()(); // 5
expr2.Compile()(); // (2 + 3) ← 運算式樹結構本身

Lambda Expression 多重身分

// 錯誤:無法隱式轉換
LambdaExpression expr = () => 2 + 3;

// 正確:建構運算式樹節點
Expression<Func<int>> expr = () => 2 + 3;
LambdaExpression node = Expression.Lambda(Expression.Add(Expression.Constant(2), Expression.Constant(3)));

// 正確:建構委托
Func<int> fn = () => 2 + 3;
Func<int> fn2 = () => { return 2 + 3; }

Query Expression 支援的 Operators

並非所有 Query Operator 皆有 Query Expression 對應,僅支援:

Select / SelectMany / Join / GroupJoin / Where / 
OrderBy / OrderByDescending / GroupBy / ThenBy / ThenByDescending

擴充 Query Expression 行為

因 Query Operator 為擴充方法,可自行實作覆蓋預設行為:

public static class QueryOperatorExt {
    public static IQueryable<T> Where<T>(this IQueryable<T> source, Expression<Func<T, bool>> predicate) {
        Console.WriteLine("Calling custom Where");
        return Queryable.Where(source, predicate);
    }
}
// 使用 Query Expression 時會呼叫自訂 Where

思考題

result1 = context.Customers.Where(condition); vs result2 = context.Customers.Where(condition.Compile()); 執行結果同為 6,但差異何在?答案見「LINQ那些事(8)」。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved