動態建立 Lambda 表示式

2021-09-08 15:44:26 字數 4646 閱讀 8107

作為 delegate 的更深度進化,lambda 讓我們的**顯得更加簡潔和優雅,但同時也面臨乙個問題,就是如何依據外部條件動態構建乙個 lambda 表示式。或許你會奇怪這個需求是如何產生的…… 首先,lambda 在 dlinq 中承擔了以往 t-sql 的部分角色;其次,在資料庫設計中,我們往往需要依據外部未知的動態條件組合來查詢資料。而問題在於作為一種靜態語言,我們顯然無法用動態語法或者拼接字串的方法來建立乙個delegate/lambda,那麼如何達到類似的目的呢?codedom?emit?或許最佳的選擇是 system.linq.expressions.expression。

首先我們看乙個簡單 lambda 表示式的構成。

i => i > 5
在這個表示式中,"i" 被稱為 parameter,"i > 5" 是 body。我們可以對 body 進行更進一步的分解,那麼 "i > 5" 分別包含引數(i)、操作符(>)以及乙個常數(5)。所有這些通過特定順序的組合,從而構建乙個完整的 lambda 表示式。

我們通過一些例子,來學習如何動態構建這些表示式。

例子1

var ints = new int ;

//var r = ints.where(i => i > 5); // 要實現的表示式

// 建立引數 i

var parameter = expression.parameter(typeof(int), "i");

// 建立常量5

var constant = expression.constant(5);

// 建立比較表示式 i > 5

var bin = expression.greaterthan(parameter, constant);

// 獲取lambda表示式

var lambda = expression.lambda>(bin, parameter);

// 通過 compile 方法獲取 delegate

var _r = ints.where(lambda.compile());

在**中設定斷點,我們可以看到偵錯程式中顯示的表示式資訊。

.net fx 3.5 中為 lambda 新增了一些委託型別。

(1) 用於處理無返回資料的 action。

public delegate void action()

public delegate void action(t arg)

public delegate void action(t1 arg1, t2 arg2)

public delegate void action(t1 arg1, t2 arg2, t3 arg3)

public delegate void action(t1 arg1, t2 arg2, t3 arg3, t4 arg4)

(2) 用於處理帶返回資料的 func。

public delegate tresult func()

public delegate tresult func(t arg)

public delegate tresult func(t1 arg1, t2 arg2)

public delegate tresult func(t1 arg1, t2 arg2, t3 arg3)

public delegate tresult func(t1 arg1, t2 arg2, t3 arg3, t4 arg4)

我們還可以進行更複雜的組合。

例子2

var ints = new int ;

// var r = ints.where(i => i > 5 && i <= 7); // 要實現的表示式

// 建立引數 i

var parameter = expression.parameter(typeof(int), "i");

// 建立表示式 i > 5

var con1 = expression.constant(5);

var bin1 = expression.greaterthan(parameter, con1);

// 建立表示式 i <= 7

var con2 = expression.constant(7);

var bin2 = expression.lessthanorequal(parameter, con2);

// 組合兩個表示式

var body = expression.and(bin1, bin2);

// 獲取 lambda 表示式

var lambda = expression.lambda>(body, parameter);

var _r = ints.where(lambda.compile());

在例子2中,我們對複雜的表示式進行了分解,並使用 and 完成多個表示式的組裝,由此我們可以建立更加複雜的邏輯組合,比如例子3。

例子3

var ints = new int ;

// var r = ints.where(i => (i > 5 && i <= 7) || (i == 3)); // 要實現的表示式

// 建立引數 i

var parameter = expression.parameter(typeof(int), "i");

// 建立表示式 i > 5

var con1 = expression.constant(5);

var bin1 = expression.greaterthan(parameter, con1);

// 建立表示式 i < 7

var con2 = expression.constant(7);

var bin2 = expression.lessthanorequal(parameter, con2);

// 建立表示式 i == 3

var con3 = expression.constant(3);

var bin3 = expression.equal(parameter, con3);

// 組合 i > 5 && i <= 7

var body = expression.and(bin1, bin2);

// 組合 ( i > 5 && i <= 7) or (i == 3)

body = expression.or(body, bin3);

var lambda = expression.lambda>(body, parameter);

var _r = ints.where(lambda.compile());

我們繼續看幾個常見的例子。

例子4

var ints = new int ;

//var r = ints.select(i => i % 2 == 0 ? i : 0); // 要實現的表示式

// 建立引數 i

var parameter = expression.parameter(typeof(int), "i");

// 建立表示式 i % 2

var con1 = expression.constant(2);

var bin1 = expression.modulo(parameter, con1);

// 建立表示式 (i % 2) == 0

var con2 = expression.constant(0);

var bin2 = expression.equal(bin1, con2);

// 建立表示式 iif(((i % 2) = 0), i, 0)

var bin3 = expression.condition(bin2, parameter, expression.constant(0));

var lambda = expression.lambda>(bin3, parameter);

var _r = ints.select(lambda.compile());

例子5

var ints = new int ;

// array.foreach(ints, i => console.writeline(i)); // 要實現的表示式

// 建立引數i

var parameter = expression.parameter(typeof(int), "i");

// 獲取 console.writeline methodinfo

methodinfo method = typeof(console).getmethod("writeline", new type );

// 建立表示式

var call = expression.call(method, parameter);

var lambda = expression.lambda>(call, parameter);

array.foreach(ints, lambda.compile());

是該花點時間去好好研究一下 system.linq.expressions namespace 了

動態建立 Lambda 表示式

首先我們看乙個簡單 lambda 表示式的構成。i i 5 在這個表示式中,i 被稱為 parameter,i 5 是 body。我們可以對 body 進行更進一步的分解,那麼 i 5 分別包含引數 i 操作符 以及乙個常數 5 所有這些通過特定順序的組合,從而構建乙個完整的 lambda 表示式。...

lambda表示式 lambda表示式

1.概述 c 11 中的 lambda 表示式用於定義並建立匿名的函式物件,以簡化程式設計工作。lambda 的語法形式如下 函式物件引數 操作符過載函式引數 mutable 或 exception 宣告 返回值型別可以看到,lambda 主要分為五個部分 函式物件引數 操作符過載函式引數 muta...

Lambda表示式和Lambda表示式樹

原版來自 linq學習筆記之二 lambda表示式和lambda表示式樹 lambda 表示式 lambda expressions 是linq實現的另一特性。lambda表示式的作用就是使用使用函式式語法,將方法實現關聯到委託例項。在使用查詢表示式 query expressions 時,查詢表示...