對於參數,需要使用Expression.Parameter建立ParameterExpression對象,注意需要在建立Lambda時傳入ParameterExpression數組才可以使參數有效。
對於本地變數,首先Expression類型提供Variable方法,但是這個Variable方法返回的也是ParameterExpression,實際上他們內部建立的都是同一種ParameterExpression對象,唯一的區別是Parameter方法會考慮Type.IsByRef的情況,但是Variable會拋出異常(如果Type.IsByRef為True)。其次需要注意的是,局部變數需要在建立BlockExpression時以ParameterExpression數組的方式傳入。
對於傳回值,需要先通過Expression.Label的部分重載建立LabelTarget對象,接著通過Expression的Return方法(間接調用MakeGoto)返回GotoExpression,注意是和一個LabelTarget對象相關聯的。最後用Expression.Label的另一部分返回LabelExpression的重載建立Label運算式,也就是Label在代碼塊中的具體位置。最後LabelTarget對象可以按照類型標記,也可以按照類型連同名稱標記。
下面代碼,我們要建立一個和如下方法類似的Lambda:
static string doo(int i)
{
string str = i.ToString();
return str;
}
全部代碼:
//+ using System.Reflection;
//+ using System.Linq.Expressions;
//參數
var pa = Expression.Parameter(typeof(int), "i");
//本地變數
var loc = Expression.Variable(typeof(string), "str");
//建立LabelTarget用來傳回值
LabelTarget labelTarget = Expression.Label(typeof(string));
//調用i.ToString()
MethodCallExpression med = Expression.Call(pa, typeof(object).GetMethod("ToString", new Type[] { }));
//將結果賦值給本地字串變數
BinaryExpression asn = Expression.Assign(loc, med);
//建立返回運算式(實際上就是Goto運算式)
GotoExpression ret = Expression.Return(labelTarget, loc);
//建立返回運算式的目標Label
LabelExpression lbl = Expression.Label(labelTarget, Expression.Constant(String.Empty));
//產生BlockExpression
BlockExpression blocks = Expression.Block(
new ParameterExpression[] { loc },
asn,
ret,
lbl);
//產生Lambda運算式
Expression<Func<int, string>> lam = Expression.Lambda<Func<int, string>>(blocks,
new ParameterExpression[] { pa });
//運行並輸出結果
Func<int, string> del = lam.Compile();
Console.WriteLine(del(17));
輸出:
17