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
原文地址:https://www.cnblogs.com/Leo_wl/p/3311253.html