.net 系列:Expression表达式树、lambda、匿名委托 的使用【转】

https://www.cnblogs.com/nicholashjh/p/7928205.html

首先定义一个泛型委托类型,如下:

public delegate T Function<T>(T a, T b);

实现泛型委托的主体代码,并调用:

 1 public static string Add(string a, string b)
 2           {
 3                 return string.Format("{0} #### {1}",a,b);
 4           }
 5  //实名委托方式
 6  Function<string> func = new Function<string>(Add);
 7  Console.WriteLine( func("hello", "world") );
 8
 9  //匿名委托方式
10  Function<string> func1 = new Function<string>(delegate(string a, string b) {
11         return string.Format("{0} @@@@ {1}",a,b);
12  });
13  Console.WriteLine(func1("hello", "world"));
14
15  //Lambda表达式方式
16  Function<string> func2 = (a, b) => string.Format("{0} **** {1}", a, b);
17  Console.WriteLine(func2("hello", "world"));
18
19  Expression<Function<string>> func2_0;
20  //func2_0 = func;  //不支持将委托直接赋值给表达式树
21  //func2_0 = func1; //不支持将委托直接赋值给表达式树
22  //func2_0 = func2; //不支持将委托直接赋值给表达式树
23
24  //(a, b) => string.Format("{0} **** {1}", a, b)语句块的类型是lambda expression,即我们常说的lambda表达式
25  //所以,func2_0 = (a, b) => string.Format("{0} **** {1}", a, b)的直接赋值是没有问题的。
26  func2_0 = (a, b) => string.Format("{0} **** {1}", a, b);
27  Console.WriteLine(func2_0.Compile()("hello", "world"));

以上代码展示了委托类型Function<T>主体定义的四种方式,分别是实名委托、匿名委托、Lambda表达式、expression表达式树。

从Function<T>委托主体的代码定义来看是越来越简单和友好,这些变化很大部分应归功于C#的语法糖。

总结:不管委托主体在编写的形式上怎么简化,但依然改变不了它委托类型的本质,当委托代码块被调用时会即时执行。

随着C#的发展,后来加入了expression这个东东,简称表达式树,我想用过ling to sql、linq to entity、linq to xml等等的你是不会陌生的。
expression是一种数据结构,我们可以将平常编写的C#语句块(或者叫表达式)的各部分进行分解并存入这个树结构当中,保存在expression树结构中的语句块是不能直接执行的。
当我们需要将expression结构中的数据抽取并还原时就需要调用expression.Compile()方法,这里我称之为编译。编译后得到的结果就是我们之前存入的语句块,这是数据结构还原成语句块的过程(这是一个比喻)。
当然将数据还原成语句块时依据解析引擎的不同会产生不同的输出结果,如果引擎是linq to sql那么解析后输出的就是可供数据库执行的sql,如果引擎是linq to xml则解析后输出的是Xpath之类的表达式(没亲自验证)

下面就请你和我一起来体验一下expression表达式数据的存储和编译输出吧!!!!仍以上面的场景为例子

 1 //expression表达式树主体构造开始
 2 ParameterExpression paramA = Expression.Parameter(typeof(object), "a"); //声明Lambda表达式中的参数表达式a
 3 ParameterExpression paramB = Expression.Parameter(typeof(object), "b"); //声明Lambda表达式中的参数表达式b
 4 ConstantExpression constantExp = Expression.Constant("{0} !!!!! {1}",typeof(string));//声明文本块常量表达式
 5 MethodCallExpression bodyExp = Expression.Call(typeof(string).GetMethod("Format", new Type[] { typeof(string), typeof(object), typeof(object) })
 6                 , new Expression[] { constantExp, paramA, paramB }); //声明String.Format()方法调用表达式
 7 //expression表达式树主体构造结束
 8
 9
10 //1.构造类型为LambdaExpression的lambda表达式树,编译后得到委托的基元类型(弱类型)。
11 LambdaExpression func3 = Expression.Lambda(bodyExp, paramA, paramB);//将以上各个表达式部分组合为Lambda表达式
12 Delegate dg = func3.Compile();//编译表达式树得到委托
13 Console.WriteLine(dg.DynamicInvoke("hello", "world"));//调用委托并将结果输出到控制台
14 //Console.WriteLine(func3.Compile().DynamicInvoke("hello", "world")); //上面两步可以简化为这句代码
15
16 //2.构造类型为Expression<Function<string>>的泛型lambda表达式树,编译后得到委托可直接调用。
17 Expression<Function<string>> func4 = Expression.Lambda<Function<string>>(bodyExp, paramA, paramB);
18 Console.WriteLine(func4.Compile()("xxxx", "yyyy"));
19
20  //3.构造类型为Expression<Func<string, string, string>>的泛型lambda表达式树,编译后得到委托可直接调用。
21  //与上面的区别是这里用系统定义的Func<in T1, in T2, out TResult>泛型委托代替了自定义的Function<T>委托。
22  Expression<Func<string, string, string>> func5 = Expression.Lambda<Func<string, string, string>>(bodyExp, paramA, paramB);
23  Console.WriteLine(func5.Compile()("yyyy", "zzzz"));
24
25  //以上总结了expression表达式的创建和调用的不同方式,以下是几个有关expression的扩展例子
26  //4.动态构造string.Concat("hello", "world")语句块
27  var concatMethod = typeof(string).GetMethod("Concat", new[] { typeof(string), typeof(string) });
28  var addExpr = Expression.Add(Expression.Constant("hello "), Expression.Constant("world"), concatMethod);
29  Expression<Func<string>> e = Expression.Lambda<Func<string>>(addExpr);
30  Console.WriteLine(e.Compile()());
31
32  //5.动态构造Math.Sin(100)语句块
33  ParameterExpression expA = Expression.Parameter(typeof(double), "a"); //参数a
34  MethodCallExpression expCall = Expression.Call(
35         typeof(Math).GetMethod("Sin",new Type[]{typeof(double)}),expA);
36  LambdaExpression exp = Expression.Lambda(expCall, expA); // a => Math.Sin(a)
37  Console.WriteLine( exp.Compile().DynamicInvoke(100) );
38
39  //6.动态构造Console.WriteLine("aaa")语句块
40  ConstantExpression _constExp = Expression.Constant("aaa", typeof(string));//一个常量
41  MethodCallExpression _methodCallexp = Expression.Call(typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }), _constExp);
42  Expression<Action> consoleLambdaExp = Expression.Lambda<Action>(_methodCallexp);
43  consoleLambdaExp.Compile()();

原文地址:https://www.cnblogs.com/mazhenyu/p/9186313.html

时间: 2024-08-16 04:56:35

.net 系列:Expression表达式树、lambda、匿名委托 的使用【转】的相关文章

委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底

本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景.各位看官,这里就不啰嗦了,直接上代码. 首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static string Add(string a, string b) { return string.Format("{0} #### {1}",a,b); } //实名委托方式 Function&

.net 系列:Expression表达式树

转至:http://www.cnblogs.com/li-peng/p/3154381.html 整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧 它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _constExp = Expression.Constant("aaa",typeof(string));//一个常量//Console.Writeline("aaa");M

C# 表达式树Lambda扩展(四)

一.前言 本来计算这篇文章在后面需要运用的时候写的,但是既然写到表达式的扩展呢,就一起写完吧. 看到这个标题就有一种疑问,Lambda表达式本来就是表达式树,还需要怎么扩展?那就看看下面的内容,你就知道了. 表达式系列目录 C# 表达式树讲解(一) C# 表达式树遍历(二) C# 表达式树分页扩展(三) 二.Lambda扩展 这里先不忙解答上面的问题,我们先看下这样一个应用场景. 一个页面的请求,里面带有一些条件查询,请求类如下 public class ScoreRequest { publi

关于Expression表达式树的拼接

最近在做项目中遇到一个问题,需求是这样的: 我要对已经存在的用户进行检索,可以根据用户的id 或者用户名其中的一部分字符来检索出来,这样就出现了三种情况 只有id,只有用户名中一部字符,或者全部都有. 我们用的MVC+EF5.0的框架,在BLL层进行查询的 时候需要构建lambda表达式来作为查询条件,但是,我们怎么来构建lambda来确定查询的条件呢?我们知道Express<Func<T,bool>>这样的一个参数可以是lambda表达式,但是这里的按条件拼接式不能使用委托链的形

Expression表达式树

表达式树表示树状数据结构的代码,树状结构中的每个节点都是一个表达式,例如一个方法调用或类似 x < y 的二元运算 1.利用 Lambda 表达式创建表达式树 Expression<Func<int, int, int, int>> expr = (x, y, z) => (x + y) / z; 2.编译表达式树,该方法将表达式树表示的代码编译成一个可执行委托 expr.Compile()(1, 2, 3) 3.IQueryable<T>的扩展方法,Whe

Expression 表达式树学习整理

整理了一下表达式树的一些东西,入门足够了 先从ConstantExpression 开始一步一步的来吧  它表示具有常量值的表达式 我们选建一个控制台应用程序 ConstantExpression _constExp = Expression.Constant("aaa",typeof(string));//一个常量 //Console.Writeline("aaa"); MethodCallExpression _methodCallexp=Expression.

Expression表达式树动态查询

在进行数据列表的查询中,我们通常会使用两种方式进行查询: linq查询 数据库sql语句查询 这样固然可以实现查询,本人之前也都是这么做的,因为查询的条件很少.使用linq,可以将所有的查询条件的属性传到后台,再根据该属性是否有值,使用where进行查询:使用存储过程,也需要将所有查询条件的属性传到后台, 再根据该属性是否有值进行sql语句的拼接.这样做在查询条件很少的时候固然没啥影响,但是有一天做查询列表的时候,本人碰到了一个查询条件高达接近10个的情况,这样再使用上述的方法固然也可以实现,但

LINQ to Objects系列(4)表达式树

position:static(静态定位) 当position属性定义为static时,可以将元素定义为静态位置,所谓静态位置就是各个元素在HTML文档流中应有的位置 podisition定位问题.所以当没有定义position属性时,并不说明该元素没有自己的位置,它会遵循默认显示为静态位置,在静态定位状态下无法通过坐标值(top,left,right,bottom)来改变它的位置. position:absolute(绝对定位) 当position属性定义为absolute时,元素会脱离文档流

什么是表达式树,它与表达式、委托有什么区别?

序言 首先,需要普及下基础知识: Expression我们称之为:表达式树, 而Func<>或者Action 称之为:匿名委托,Func与Action的区别是Func带返回值(至少一个参数),Action不带返回值(可以没有任何参数). 以上的关键词是在.net 3.5之后出现的,配合Linq中Lambda使用. 当然Expression还可以动态的进行构造它,而不使用Lambda表达式来定义. 什么是表达式树 它是一种数据结构体,用于存储需要计算.运算的一种结构.这种结构可以只是”存储“,而