本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景。各位看官,这里就不啰嗦了,直接上代码。

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

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<string> func = new Function<string>(Add);
Console.WriteLine( func("hello", "world") ); //匿名委托方式
Function<string> func1 = new Function<string>(delegate(string a, string b) {
return string.Format("{0} @@@@ {1}",a,b);
});
Console.WriteLine(func1("hello", "world")); //Lambda表达式方式
Function<string> func2 = (a, b) => string.Format("{0} **** {1}", a, b);
Console.WriteLine(func2("hello", "world")); Expression<Function<string>> func2_0;
//func2_0 = func; //不支持将委托直接赋值给表达式树
//func2_0 = func1; //不支持将委托直接赋值给表达式树
//func2_0 = func2; //不支持将委托直接赋值给表达式树 //(a, b) => string.Format("{0} **** {1}", a, b)语句块的类型是lambda expression,即我们常说的lambda表达式
//所以,func2_0 = (a, b) => string.Format("{0} **** {1}", a, b)的直接赋值是没有问题的。
func2_0 = (a, b) => string.Format("{0} **** {1}", a, b);
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表达式数据的存储和编译输出吧!!!!仍以上面的场景为例子。

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

关于xx.Where(Func<T,bool> predicate)和xx.Where(Expression<Func<T, bool>> predicate)的一点看法

 //一般用在对内存对象的筛选场景下,语句被调用后即时执行并对数据进行筛选
public static IEnumerable<string> Where(Func<string,bool> predicate)
{
List<string> lst = new List<string>();
lst.Add("aaa");
lst.Add("bbb");
lst.Add("ccc");
IEnumerable<string> rs = lst.Where(predicate);
return rs;
} //基于表达式树级别的条件筛选(比如linq to entity),表达式树只是sql语句逻辑关系的容器,最终的sql语句在表达式树被编译调用后才得到。
public static IQueryable<string> Where(Expression<Func<string, bool>> predicate)
{
List<string> lst = new List<string>();
lst.Add("aaa");
lst.Add("bbb");
lst.Add("ccc");
IQueryable<string> rs = lst.AsQueryable().Where(predicate);
return rs;
}

委托、匿名委托、Lambda 表达式、Expression表达式树之刨根问底的更多相关文章

  1. (28)C#委托,匿名函数,lambda表达式,事件

    一.委托 委托是一种用于封装命名和匿名方法的引用类型. 把方法当参数,传给另一个方法(这么说好理解,但实际上方法不能当参数,传入的是委托类型),委托是一种引用类型,委托里包含很多方法的引用 创建的方法 ...

  2. 委托-异步调用-泛型委托-匿名方法-Lambda表达式-事件【转】

    1. 委托 From: http://www.cnblogs.com/daxnet/archive/2008/11/08/1687014.html 类是对象的抽象,而委托则可以看成是函数的抽象.一个委 ...

  3. C#多线程+委托+匿名方法+Lambda表达式

    线程 下面是百度写的: 定义英文:Thread每个正在系统上运行的程序都是一个进程.每个进程包含一到多个线程.进程也可能是整个程序或者是部分程序的动态执行.线程是一组指令的集合,或者是程序的特殊段,它 ...

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

    首先定义一个泛型委托类型,如下: public delegate T Function<T>(T a, T b); 实现泛型委托的主体代码,并调用: public static strin ...

  5. Unity C# 多态 委托 事件 匿名委托 Lambda表达式 观察者模式 .NET 框架中的委托和事件

    一.多态 里氏替换原则: 任何能用基类的地方,可以用子类代替,反过来不行.子类能够在基类的基础上增加新的行为.面向对象设计的基本原则之一. 开放封闭原则: 对扩展开放,意味着有新的需求或变化时,可以对 ...

  6. C#学习笔记(十七):委托、事件、观察者模式、匿名委托和lambert表达式

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  7. 深入学习C#匿名函数、委托、Lambda表达式、表达式树类型——Expression tree types

    匿名函数 匿名函数(Anonymous Function)是表示“内联”方法定义的表达式.匿名函数本身及其内部没有值或者类型,但是可以转换为兼容的委托或者表达式树类型(了解详情).匿名函数转换的计算取 ...

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

    https://www.cnblogs.com/nicholashjh/p/7928205.html 首先定义一个泛型委托类型,如下: public delegate T Function<T& ...

  9. 第十五节:Expression表达式目录树(与委托的区别、自行拼接、总结几类实例间的拷贝)

    一. 基本介绍 回忆: 最早接触到表达式目录树(Expression)可能要追溯到几年前使用EF早期的时候,发现where方法里的参数是Expression<Func<T,bool> ...

随机推荐

  1. 使用 Intellij Idea 导出JavaDoc

    使用/* ...... /来注释代码,解释方法参数,返回参数,类的功能及用法. 常用的注释标签: @author 作者 @version 版本 @see 参考转向 @param 参数说明 @retur ...

  2. NHibernate系列文章十九:NHibernate关系之多对多关系(附程序下载)

    摘要 NHibernate的多对多关系映射由many-to-many定义. 从这里下载本文的代码NHibernate Demo 1.修改数据库 添加Product表 添加ProductOrder表 数 ...

  3. linux grep命令详解

    linux grep命令详解 简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来 ...

  4. C语言的time.h解释python的time

    clock_t clock(void),对比python的clock() 返回程序执行的时间,clock_t的实际类型是long #include<Windows.h> Sleep(); ...

  5. rtmp拉流测试工具

    http://www.cutv.com/demo/live_test.swf ================================================== ========== ...

  6. 使用Synplify综合时保留logic

    在使用Synplify综合时,此工具会自动优化我的设计. 当然此功能有好有坏,最近有个项目需要使用Chipscope观察内部信号,打开inserter就懵了,信号列表中我的设计有的是名字被改了,有的是 ...

  7. 【转载】Java常量池

    本篇随笔为转载,原贴地址:Java常量池理解与总结. (其实Java的常量池有点像C++中的存储字符串常量的常量存储区). 一.相关概念 什么是常量用final修饰的成员变量表示常量,值一旦给定就无法 ...

  8. 文件读写方法1.FileInputStream和FileOutputStream

    package fileTest; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundEx ...

  9. ORACLE 回收站导致的故障

    ORACLE 回收站导致的故障 一.故障 (1)现象     一个生产环境,oracle数据库挂死,严重影响生产.查死锁sql,发现大量日志插入语句,并且每条运行时间都超过一分钟,插入非常缓慢.据分析 ...

  10. dmesg

    在开机的时候你会发现有很多的讯息出现吧,例如 CPU 的形式.硬盘. 光盘型号及硬盘分割表等等,这 些信息的产生都是核心 (kernel) 在进行硬件的测试与驱动啦.要看这些讯息你可以用 dmesg  ...