zoukankan      html  css  js  c++  java
  • C#中的表达式树的浅解

    表达式树可以说是Linq的核心之一,为什么是Linq的核心之一呢?因为表达式树使得c#不再是仅仅能编译成IL,我们可以通过c#生成一个表达式树,将结果作为一个中间格式,在将其转换成目标平台上的本机语言。比如SQL。我们常用的Linq to sql就是这样生成SQL的。

    表达式树是.NET 3.5之后引入的,它是一个强大灵活的工具(比如用在LINQ中构造动态查询)。

    先来看看Expression类的API接口:

    namespace System.Linq.Expressions
    {
        //
        // 摘要:
        //     以表达式目录树的形式将强类型 lambda 表达式表示为数据结构。此类不能被继承。
        //
        // 类型参数:
        //   TDelegate:
        //     System.Linq.Expressions.Expression`1 表示的委托的类型。
        public sealed class Expression<TDelegate> : LambdaExpression
        {
            //
            // 摘要:
            //     将表达式树描述的 lambda 表达式编译为可执行代码,并生成表示该 lambda 表达式的委托。
            //
            // 返回结果:
            //     一个 TDelegate 类型的委托,它表示由 System.Linq.Expressions.Expression`1 描述的已编译的 lambda 表达式。
            public TDelegate Compile();
            //
            // 摘要:
            //     生成表示 lambda 表达式的委托。
            //
            // 参数:
            //   debugInfoGenerator:
            //     编译器用于标记序列点并批注局部变量的调试信息生成器。
            //
            // 返回结果:
            //     包含 lambda 的已编译版本的委托。
            public TDelegate Compile(DebugInfoGenerator debugInfoGenerator);
            //
            // 摘要:
            //     创建一个与此表达式类似的新表达式,但使用所提供的子级。如果所有子级都相同,则将返回此表达式。
            //
            // 参数:
            //   body:
            //     结果的 System.Linq.Expressions.LambdaExpression.Body 属性。
            //
            //   parameters:
            //     结果的 System.Linq.Expressions.LambdaExpression.Parameters 属性。
            //
            // 返回结果:
            //     此表达式(如果未更改任何子级),或带有更新的子级的表达式。
            public Expression<TDelegate> Update(Expression body, IEnumerable<ParameterExpression> parameters);
            protected internal override Expression Accept(ExpressionVisitor visitor);
        }
    }

    表达式树的语法如下:

    Expression<Func<type,returnType>> = (param) => lamdaexpresion;

    例如:

    Expression<Func<int, int, int>> expr = (x, y) => x+y;

    我们运行以上代码,并在VS调试模似下查看这个表达式树:

    image

    可以看到表达式树主要由下面四部分组成:

    1、Body 主体部分

    2、Parameters 参数部分

    3、NodeType 节点类型

    4、Lambda表达式类型

    在上述代码中,主体即为:x+y,参数为(x,y),NodeType为Lambda表达式,返回值为int

    主体部分可以是表达式,但是不能包含语句。例如:我定义一个委托,Lambda表达式可以这样写

    Func<int, int, int> func = (x, y) => x + y;

    也可以这样写:

    Func<int, int, int> func = (x, y) => { return x + y; };

    但是,在表达式树种,只能用第一种写法,如果使用第二种写法编译汇报错误:无法将具有语句体的 lambda 表达式转换为表达式树

    除了上边的写法,表达式树还有可以这么写:

    ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数
    ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数
    
    BinaryExpression bexp = Expression.Add(pex1, pex2);//加法
    
    var lambdaExp = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] {pex1,pex2 });

    VS调试模式下可以看到两种写法生成的表达式树是一样的

    将表达式树编译成委托

    LambdaExpression是从Expression派生的类型。泛型类Expression<TDelegate>是从LambdaExpression派生的,其中泛型参数TDelegate必须是委托类型。

    LambdaExpression有个Compile方法能创建恰当类型的一个委托。而Expression<TDelegate>的Compile方法返回TDelegate类型的委托。来看看下面的例子:

    Expression<Func<int, int, int>> expr = (x, y) => x + y;
    
    ParameterExpression pex1 = Expression.Parameter(typeof(int), "x");//第一个参数
    ParameterExpression pex2 = Expression.Parameter(typeof(int), "y");//第二个参数
    
    BinaryExpression bexp = Expression.Add(pex1, pex2);//主体,加法
    
    //使用Expression.Lambda方法,创建一个委托类型已知的Expression
    Expression<Func<int,int,int>> lambdaExp 
        = Expression.Lambda<Func<int, int, int>>(bexp, new ParameterExpression[] { pex1, pex2 });
    
    Func<int,int,int> tDelegate = lambdaExp.Compile();//编译成委托
    
    Console.WriteLine(tDelegate(1, 3));
    
    Console.Read();

    我们运行上面代码,结果为:4。我们写了一大堆代码,本质上就是用表达式树计算了1+3的结果。

  • 相关阅读:
    toj 2819 Travel
    toj 2807 Number Sort
    zoj 2818 Prairie dogs IV
    zoj 1276 Optimal Array Multiplication Sequence
    toj 2802 Tom's Game
    toj 2798 Farey Sequence
    toj 2815 Searching Problem
    toj 2806 Replace Words
    toj 2794 Bus
    css截取字符
  • 原文地址:https://www.cnblogs.com/jimmy-y/p/5417858.html
Copyright © 2011-2022 走看看