close
文章出處

裝配腦袋的習題在這里:Expression Tree上手指南 (一)

不了解Expression Tree的同學可以去看下,很好,很強大。

1: -a
2: a + b * 2
 
我把這些問題都弄成了方法,分別是Question1,Question2,….QuestionX
 

第一題:-a

 
因為實在是太短了,我不明白是什么意思,姑且認為是做取反操作吧,也就是假如輸入是5,那么輸出是-5.
如果讓你寫lambda表達式,估計沒幾個人寫不出來吧:(a)=>{return –a;}
當然你可以簡短點:(a)=>{-a}
 
OK,看一看lambda表達式:(a)=>{return –a;},可以知道有一個參數a,輸出是-a。
參數是ParameterExpression.
 
所以Question1里面基本代碼是:
private static void Question1()
        {
            ParameterExpression expPara = Expression.Parameter(typeof(int), "a");
        }
 
先聲明一個參數a。類型是int.
接著應該對參數求反。那么我們應該使用求反表達式了。
在Msdn 里面的ExpressionType 里面可以查到
image 
當然在Expression里面你也可以找到下面的方法:
public static UnaryExpression Negate(Expression expression);
 
于是代碼可以修改為:
 
private static void Question1()
 {
      ParameterExpression expPara = Expression.Parameter(typeof(int), "a");
      UnaryExpression expNegate = Expression.Negate(expPara);
}

 

OK,剩下的就是生成lambda表達式了,

使用Expression.Lambda方法就可以生成了。lambda表達式最關鍵的是參數和body。

參數是(a).所以傳遞的是expPara.

body就是lambda表達式的主體,你可以認為是{}之間的代碼,在這里傳遞的是expNegate.

 

為什么要生成lambda表達式??

因為可以編譯lambda表達式生成委托。

 

private static void Question1()
{
    int a = 5;

    ParameterExpression expPara = Expression.Parameter(typeof(int), "a");
    UnaryExpression expNegate = Expression.Negate(expPara);
    LambdaExpression expLmd = Expression.Lambda(expNegate, expPara);
}
有了lambdaExpression后,就可以編譯LambdaExpression了。
private static void Question1()
{
    int a = 5;

    ParameterExpression expPara = Expression.Parameter(typeof(int), "a");
    UnaryExpression expNegate = Expression.Negate(expPara);
    LambdaExpression expLmd = Expression.Lambda(expNegate, expPara);

    Console.WriteLine(expLmd.Compile().DynamicInvoke(a));
}

運行結果如下:
image 
 
DynamicInvoke的方法簽名如下:
 
//動態調用(后期綁定)由當前委托所表示的方法。
[SecuritySafeCritical]
public object DynamicInvoke(params object[] args);
 
DynamicInvoke是后期綁定,所以性能比較差。
 
因為我們知道編譯后的expLmd.的參數類型是int,結果是int.
所以我們可以將委托轉換為Func<int,int>的強類型的委托。
 
private static void Question1()
{
    int a = 5;

    ParameterExpression expPara = Expression.Parameter(typeof(int), "a");
    UnaryExpression expNegate = Expression.Negate(expPara);
    LambdaExpression expLmd = Expression.Lambda(expNegate, expPara);

    Console.WriteLine(expLmd.Compile().DynamicInvoke(a));

    Func<int, int> funcQuestion1 = expLmd.Compile() as Func<int, int>;
    Console.WriteLine(funcQuestion1(a));
}
 

第二題:a + b * 2

 

第一步,如果你寫lambda表達式,你應該怎么寫??

(int a,int b)=>{return a+ b *2;}

好了,會寫lambda表達式,基本上你也應該會寫Expression了。

 

參數:int a,int b;

body:return a+b*2;

 

private static void Question2()
{
    ParameterExpression expA = Expression.Parameter(typeof(int), "a");
    ParameterExpression expB = Expression.Parameter(typeof(int), "b");
}

 

聲明兩個變量a,b類型是int.

接著要寫body了。

body是a+b*2.

在這里2是常量。首先想到的是查看ExpressionType,看看有沒有什么表達式代表的是常量,當然你可以找到ConstantExpression

 

于是代碼變成了:

private static void Question2()
{
    ParameterExpression expA = Expression.Parameter(typeof(int), "a");
    ParameterExpression expB = Expression.Parameter(typeof(int), "b");
    ConstantExpression exp2 = Expression.Constant(2);
}



接著用()來分隔下a+b*2.

()的意思是先執行什么,后執行什么。

 

結果如下  a + (b *2)

先執行b*2,然后將b*2的結果和a相加。

 

Expression expBody = Expression.Add(expA, 
                Expression.MakeBinary(ExpressionType.Multiply, expB, exp2));
 
Expression.MakeBinary(ExpressionType.Multiply, expB, exp2))
將expB和exp2進行相乘操作。然后和expA做相加操作。生成的就是expBody了。
 
因為我們知道參數是(int,int), 結果是int
所以委托的類型是Func<int,int,int>
 
完整的代碼如下:
private static void Question2()
{
    ParameterExpression expA = Expression.Parameter(typeof(int), "a");
    ParameterExpression expB = Expression.Parameter(typeof(int), "b");
    ConstantExpression exp2 = Expression.Constant(2);

    Expression expBody = Expression.Add(expA, Expression.MakeBinary(
        ExpressionType.Multiply, expB, exp2));

    Expression<Func<int, int, int>> lmd = Expression.Lambda<Func<int, int, int>>
        (expBody, expA, expB);

    Console.WriteLine(lmd.Compile()(3, 2));
}
 

不含病毒。www.avast.com
arrow
arrow
    全站熱搜

    AutoPoster 發表在 痞客邦 留言(0) 人氣()