C#表达式树的初步了解

  在很早之前就据说过表达式树了,但并无去了解它。虽然本身用过linq to sql和linq to entity,但也就用着就用着,并无去深究c#代码怎么会生成sql代码而不是IL。废话很少说了,开写吧!sql

.net里表达式树核心概念就是:将代码做为数据。它将一些代码表示为一个对象树,树中的每一个节点自己都是一个表达式,不一样的表达式类型表明能在代码中执行不一样操做:二元操做,一元操做,方法调用等等。express

  System.Linq.Expressions命名空间包含了表明表达式的各个类。全部的表达式类都从Expression类派生,Expression是个抽象类,主要包含的是一些静态的方法,这些方法用于生成其余表达式类的实例。Expression类还包含了两个重要属性:c#

  1.Type属性:表明了表达式求值结果的类型。好比,一个表达式是要获取一个字符串的Length属性,那么该表达式的Type属性应为int类型spa

  2.NodeType属性:表明了表达式的种类。这个种类表示成ExpressionType枚举的一个成员:LessThan,Invoke,Multiply,MemberAccess等等(有80几种,汗!)。.net

 

一个表达式树的简单例子                                                                                                   code

    static void Main(string[] args)
    {
        Expression firstArg = Expression.Constant(2);
        Expression secondArg = Expression.Constant(4);
        Expression add = Expression.Add(firstArg, secondArg);

        Console.WriteLine(add);
    } 

输出结果:对象

上面的代码将会生成以下图的表达式树:blog

值得注意的是,表达式中“叶”表达式在代码中是最早建立的:表达式是自下而上构建的。这是由“表达式不易变”这一事实实现的。ip

将表达式树编译成委托                                                                                                       字符串

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

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

    static void Main(string[] args)
    {
        Expression firstArg = Expression.Constant(2);
        Expression secondArg = Expression.Constant(4);
        Expression add = Expression.Add(firstArg, secondArg);

        Expression<Func<int>> func = Expression.Lambda<Func<int>>(add);
        Func<int> compiled = func.Compile();
        Console.WriteLine(compiled());
    }

咱们经过Expression.Lambda<TDelegate>(Expression expression)方法来建立Expression<TDelegate>类型对象,再调用其Compile方法获取表达式树编译出的委托实例。

将C# Lambda表达式转换成表达式树                                                                                   

咱们知道Lambda表达式能显示或隐式地转换成恰当的委托实例。可是,编译器也能很轻松的将Lambda表达式构建为一个表达式树:

//将Lambda表达式转换成表达式树
Expression<Func<int>> return5 = () => 5;

可是,并非全部的Lambda表达式都能转换成表达式树,有一些限制:不能将带有一个语句块的Lambda转换成一个表达式树-----只有对单个表达式进行求值得Lambda才能够。表达式中不能包含赋值操做,由于表达式树中表示不了这种操做。还有其余一些较少见的限制,总而言之,若是存在转换问题,你会在编译时发现。 

位于Linq核心的表达式树                                                                                                    

表达式树能够说是Linq的核心之一,为何是Linq的核心之一呢?由于表达式树使得c#再也不是仅仅能编译成IL,咱们能够经过c#生成一个表达式树,将结果做为一个中间格式,在将其转换成目标平台上的本机语言。好比SQL。咱们经常使用的Linq to sql就是这样生成SQL的。

下图展现了Linq to Objects和Linq to SQL的不一样路径:

资料参考于《深刻理解c#》第二版

相关文章
相关标签/搜索