快速上手Expression Tree(一):做一做装配脑袋的Expression Tree 习题

装配脑袋的习题在这里: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));
}
posted @ 2012-04-11 08:33  awp110  阅读(311)  评论(0编辑  收藏  举报