本篇不是对标题所述之概念的入门文章,重点在阐述它们的异同点和应用场景。各位看官,这里就不啰嗦了,直接上代码。
首先定义一个泛型委托类型,如下:
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表达式数据的存储和编译输出吧!!!!仍以上面的场景为例子。
关于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; }