• C#表达式树的初步了解


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

     

    深入理解C#中this/partial/null的使用

    一、this关键字作用

     

    1、this表示当前运行中的对象

     

    Eg:

     

     View Code

    public class Person

    {

    public int age;

    public string name;

    public Person(int age,string name)

    {

    this.age=age;//把传递进来的12赋值给当前运行在内存中的对象的age属性,下同

    this.name=name;

    Console.WriteLine("两个参数的构造函数被调用了");


    }

    static void Main(string[] args)

    {

    Person p=new Person(12,"Lucy");

    }

    }

     

     2、调用其他的构造函数

     

    如上例再加上:

     

     View Code

    public Person(int age)

    {

    this.age=age;

    Console.WriteLine("只有一个参数,并且参数类型是int类型的构造函数被调用了");

    }

    //this调用

    public Person(int age,string name):this(age)

    { //this.age=age; this.name=name;


    Console.WriteLine("两个参数的构造函数被调用了");
    }
    //调用

    static void Main(string[] args)

    {
    Person p=new Person(12,"Lucy");//先调用两个参数的构造函数,再调用一个参数的构造函数,再执行一个参数的构造函数,在执行两个参数的构造函数
    }

     

     二、部分类

     

    1、必须在同一个命名空间中,类的名字要一致,被partial修饰的类叫做部分类,或伙伴类。

     

    2、C#编译器在编译伙伴类的时候会编译成1一个类,所以在另外1个伙伴类中定义的变量可以在这个伙伴类中方法。

     

    3、作用是分开管理,便于维护。

     

     View Code

    partial class Program

    {

    int num;

    }

    partial class Program

    {

    public void Test()

    {

    this.num=12;

    }

    }

     

     三、理解null

     

    1、局部变量的值类型存在栈里面,引用类型存在堆里面。成员字段,不管是引用类型还是值类型都是存在堆里面对象里面。

     

     

    2、理解一下代码

     

     View Code

    public class Person

    {
    string name;

    public Dog dog=new Dog();

    }

    public class Dog

    {

    public void Shot()

    {

    Console.WriteLine("旺旺");

    }

    }

    static void Main(string[] args)

    {

    Person d=new Person();

    d.dog.Shot();

    }

     

     

    3、只有引用类型的变量的值才能为null,值类型不能,引用类型的变量的值为null,就代表变量不指向空间中任何对象。

     

    Person p=null;
    
    Person.name="jack";//p变量没有指向任何对象,所以不能成功赋值,这时候会报“未将对象引用设置到对象的实例”

     

     

    声明:以上内容均属软谋原创,如需转载,请注明出处。

     

     

     

     

     

     

     

     

     

     

    分类: .NET
    标签: ASP.NETC#

     
     
    标签: 表达式树c#linq
  • 相关阅读:
    集合关系运算 交、差、并集
    字符串 数字 列表 元祖 字典 的不同分类and集合的概念
    我的python之路6(基础练习)
    我的python之路6(整理)
    编写Linux下socket协议TCP和UDP的Client Server程序
    linux添加新用户
    HTML5怎样在网页中使用摄像头功能 时间:2013-04-10 19:56 来源:18素材
    boost 同步定时器
    C++的multiple definition of *** first defined here错误
    TCP与UDP的区别,以及它们各自的定义
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3311253.html
Copyright © 2020-2023  润新知