詳解C# Lambda表達(dá)式的動(dòng)態(tài)生成
對(duì)于C# Lambda的理解我們?cè)谥暗奈恼轮幸呀?jīng)講述過(guò)了,那么作為Delegate的進(jìn)化使用,為了讓代碼簡(jiǎn)潔和優(yōu)雅的呈現(xiàn),C# Lambda表達(dá)式的使用功不可滅,那么依托外部條件如何動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式呢。下面讓我們來(lái)具體的看看實(shí)施。
或許你會(huì)奇怪這個(gè)需求是如何產(chǎn)生的…… 首先,Lambda 在 DLinq 中承擔(dān)了以往 T-SQL 的部分角色;其次,在數(shù)據(jù)庫(kù)設(shè)計(jì)中,我們往往需要依據(jù)外部未知的動(dòng)態(tài)條件組合來(lái)查詢(xún)數(shù)據(jù)。而問(wèn)題在于作為一種靜態(tài)語(yǔ)言,我們顯然無(wú)法用動(dòng)態(tài)語(yǔ)法或者拼接字符串的方法來(lái)創(chuàng)建一個(gè)Delegate/Lambda,那么如何達(dá)到類(lèi)似的目的呢?CodeDom?Emit?或許最佳的選擇是 System.Linq.Expressions.Expression。
1、首先我們了解一個(gè)簡(jiǎn)單C# Lambda表達(dá)式的構(gòu)成。
- i => i > 5
在這個(gè)表達(dá)式中,"i" 被稱(chēng)為 Parameter,"i > 5" 是 Body。我們可以對(duì) Body 進(jìn)行更進(jìn)一步的分解,那么 "i > 5" 分別包含參數(shù)(i)、操作符(>)以及一個(gè)常數(shù)(5)。所有這些通過(guò)特定順序的組合,從而構(gòu)建一個(gè)完整的 Lambda 表達(dá)式。
2、我們通過(guò)一些例子,來(lái)學(xué)習(xí)如何動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式。
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式例子1
- var ints =
- new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- //var r = ints.Where(i => i > 5);
- // 要實(shí)現(xiàn)的表達(dá)式
- // 創(chuàng)建參數(shù) i
- var parameter =
- Expression.Parameter(typeof(int), "i");
- // 創(chuàng)建常量5
- var constant =
- Expression.Constant(5);
- // 創(chuàng)建比較表達(dá)式 i > 5
- var bin =
- Expression.GreaterThan(parameter, constant);
- // 獲取Lambda表達(dá)式
- var lambda =
- Expression.Lambda<Func<int, bool>>(bin, parameter);
- // 通過(guò) Compile 方法獲取 Delegate
- var _r = ints.Where(lambda.Compile());
在代碼中設(shè)置斷點(diǎn),我們可以看到調(diào)試器中顯示的表達(dá)式信息。
圖1
.NET FX 3.5 中為 Lambda 新增了一些委托類(lèi)型。
(1) 用于處理無(wú)返回?cái)?shù)據(jù)的 Action。
- public delegate void
- Action()
- public delegate void
- Action<T> (T arg)
- public delegate void
- Action<T1, T2> (T1 arg1, T2 arg2)
- public delegate void
- Action<T1, T2, T3>
- (T1 arg1, T2 arg2, T3 arg3)
- public delegate void
- Action<T1, T2, T3, T4>
- (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
(2) 用于處理帶返回?cái)?shù)據(jù)的 Func。
- public delegate TResult
- Func<TResult> ()
- public delegate TResult
- Func<T, TResult> (T arg)
- public delegate TResult
- Func<T1, T2, TResult>
- (T1 arg1, T2 arg2)
- public delegate TResult
- Func<T1, T2, T3, TResult>
- (T1 arg1, T2 arg2, T3 arg3)
- public delegate TResult
- Func<T1, T2, T3, T4, TResult>
- (T1 arg1, T2 arg2, T3 arg3, T4 arg4)
我們還可以進(jìn)行更復(fù)雜的組合。
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式例子2
- var ints =
- new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- // var r =
- ints.Where(i => i > 5 && i <= 7);
- // 要實(shí)現(xiàn)的表達(dá)式
- // 創(chuàng)建參數(shù) i
- var parameter =
- Expression.Parameter(typeof(int), "i");
- // 創(chuàng)建表達(dá)式 i > 5
- var con1 =
- Expression.Constant(5);
- var bin1 =
- Expression.GreaterThan(parameter, con1);
- // 創(chuàng)建表達(dá)式 i <= 7
- var con2 =
- Expression.Constant(7);
- var bin2 =
- Expression.LessThanOrEqual(parameter, con2);
- // 組合兩個(gè)表達(dá)式
- var body =
- Expression.And(bin1, bin2);
- // 獲取 Lambda 表達(dá)式
- var lambda =
- Expression.Lambda<Func<int, bool>>(body, parameter);
- var _r = ints.Where(lambda.Compile());
在例子2中,我們對(duì)復(fù)雜的表達(dá)式進(jìn)行了分解,并使用 And 完成多個(gè)表達(dá)式的組裝,由此我們可以創(chuàng)建更加復(fù)雜的邏輯組合,比如例子3。#p#
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式例子3
- var ints =
- new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- // var r =
- ints.Where(i => (i > 5 && i <= 7) || (i == 3));
- // 要實(shí)現(xiàn)的表達(dá)式
- // 創(chuàng)建參數(shù) i
- var parameter =
- Expression.Parameter(typeof(int), "i");
- // 創(chuàng)建表達(dá)式 i > 5
- var con1 =
- Expression.Constant(5);
- var bin1 =
- Expression.GreaterThan(parameter, con1);
- // 創(chuàng)建表達(dá)式 i < 7
- var con2 =
- Expression.Constant(7);
- var bin2 =
- Expression.LessThanOrEqual(parameter, con2);
- // 創(chuàng)建表達(dá)式 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<Func<int, bool>>
- (body, parameter);
- var _r = ints.Where(lambda.Compile());
我們繼續(xù)看幾個(gè)常見(jiàn)的例子。
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式例子4
- var ints =
- new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- //var r = ints.Select(i => i % 2 == 0 ? i : 0);
- // 要實(shí)現(xiàn)的表達(dá)式
- // 創(chuàng)建參數(shù) i
- var parameter =
- Expression.Parameter(typeof(int), "i");
- // 創(chuàng)建表達(dá)式 i % 2
- var con1 =
- Expression.Constant(2);
- var bin1 =
- Expression.Modulo(parameter, con1);
- // 創(chuàng)建表達(dá)式 (i % 2) == 0
- var con2 =
- Expression.Constant(0);
- var bin2 =
- Expression.Equal(bin1, con2);
- // 創(chuàng)建表達(dá)式 IIF(((i % 2) = 0), i, 0)
- var bin3 =
- Expression.Condition
- (bin2, parameter, Expression.Constant(0));
- var lambda =
- Expression.Lambda<Func<int, int>>(bin3, parameter);
- var _r = ints.Select(lambda.Compile());
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式例子5
- var ints =
- new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- // Array.ForEach<int>(ints, i => Console.WriteLine(i));
- // 要實(shí)現(xiàn)的表達(dá)式
- // 創(chuàng)建參數(shù)i
- var parameter =
- Expression.Parameter(typeof(int), "i");
- // 獲取 Console.WriteLine MethodInfo
- MethodInfo method =
- typeof(Console).GetMethod(
- "WriteLine", new Type[] { typeof(int) });
- // 創(chuàng)建表達(dá)式
- var call = Expression.Call(method, parameter);
- var lambda =
- Expression.Lambda<Action<int>>(call, parameter);
- Array.ForEach<int>(
- ints, lambda.Compile());
是該花點(diǎn)時(shí)間去好好研究一下 System.Linq.Expressions Namespace 了……
動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式的基本內(nèi)容就向你介紹到這里,希望那個(gè)對(duì)你了解和掌握使用動(dòng)態(tài)構(gòu)建C# Lambda表達(dá)式有所幫助。
【編輯推薦】