zoukankan      html  css  js  c++  java
  • C#表达式树的初步了解

      在很早以前就听说过表达式树了,但并没有去了解它。虽然自己用过linq to sql和linq to entity,但也就用着就用着,并没有去深究c#代码怎么会生成sql代码而不是IL。废话不多说了,开写吧!

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

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

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

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

    一个表达式树的简单例子                                                                                                   

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

    输出结果:

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

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

    将表达式树编译成委托                                                                                                       

    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#》第二版

  • 相关阅读:
    Android studio 安装已经下载好的gradle.zip文件【ubuntu 14.04 LTS环境】
    Python 2.7.6 安装lxml模块[ubuntu14.04 LTS]
    ubuntu14.04 LTS Python IDE专用编辑器PyCharm开发环境搭建
    Git 创建两个“本地分支”协同工作
    关于refs/for/ 和refs/heads/
    Git 多人协作开发的过程
    gerrit_bash_commands.sh
    Ubuntu Eclipse配置Python开发环境
    看看你那张熬完夜的脸
    2016-01-24
  • 原文地址:https://www.cnblogs.com/hao-dotnet/p/3310907.html
Copyright © 2011-2022 走看看