您的位置:首页 > 其它

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

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

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

publicdelegateTFunction<T>(Ta,Tb);
实现泛型委托的主体代码,并调用:




  publicstaticstringAdd(stringa,stringb)
  {
    returnstring.Format("{0}####{1}",a,b);
  }

//实名委托方式
Function<string>func=newFunction<string>(Add);
Console.WriteLine(func("hello","world"));

//匿名委托方式
Function<string>func1=newFunction<string>(delegate(stringa,stringb){
returnstring.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)语句块的类型是lambdaexpression,即我们常说的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这个东东,简称表达式树,我想用过lingtosql、linqtoentity、linqtoxml等等的你是不会陌生的。
expression是一种数据结构,我们可以将平常编写的C#语句块(或者叫表达式)的各部分进行分解并存入这个树结构当中,保存在expression树结构中的语句块是不能直接执行的。
当我们需要将expression结构中的数据抽取并还原时就需要调用expression.Compile()方法,这里我称之为编译。编译后得到的结果就是我们之前存入的语句块,这是数据结构还原成语句块的过程(这是一个比喻)。
当然将数据还原成语句块时依据解析引擎的不同会产生不同的输出结果,如果引擎是linqtosql那么解析后输出的就是可供数据库执行的sql,如果引擎是linqtoxml则解析后输出的是Xpath之类的表达式(没亲自验证)

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



//expression表达式树主体构造开始
ParameterExpressionparamA=Expression.Parameter(typeof(object),"a");//声明Lambda表达式中的参数表达式a
ParameterExpressionparamB=Expression.Parameter(typeof(object),"b");//声明Lambda表达式中的参数表达式b
ConstantExpressionconstantExp=Expression.Constant("{0}!!!!!{1}",typeof(string));//声明文本块常量表达式
MethodCallExpressionbodyExp=Expression.Call(typeof(string).GetMethod("Format",newType[]{typeof(string),typeof(object),typeof(object)})
,newExpression[]{constantExp,paramA,paramB});//声明String.Format()方法调用表达式
//expression表达式树主体构造结束

//1.构造类型为LambdaExpression的lambda表达式树,编译后得到委托的基元类型(弱类型)。
LambdaExpressionfunc3=Expression.Lambda(bodyExp,paramA,paramB);//将以上各个表达式部分组合为Lambda表达式
Delegatedg=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<inT1,inT2,outTResult>泛型委托代替了自定义的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")语句块
varconcatMethod=typeof(string).GetMethod("Concat",new[]{typeof(string),typeof(string)});
varaddExpr=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)语句块
ParameterExpressionexpA=Expression.Parameter(typeof(double),"a");//参数a
MethodCallExpressionexpCall=Expression.Call(
typeof(Math).GetMethod("Sin",newType[]{typeof(double)}),expA);
LambdaExpressionexp=Expression.Lambda(expCall,expA);//a=>Math.Sin(a)
Console.WriteLine(exp.Compile().DynamicInvoke(100));

//6.动态构造Console.WriteLine("aaa")语句块
ConstantExpression_constExp=Expression.Constant("aaa",typeof(string));//一个常量
MethodCallExpression_methodCallexp=Expression.Call(typeof(Console).GetMethod("WriteLine",newType[]{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)的一点看法



//一般用在对内存对象的筛选场景下,语句被调用后即时执行并对数据进行筛选
publicstaticIEnumerable<string>Where(Func<string,bool>predicate)
{
List<string>lst=newList<string>();
lst.Add("aaa");
lst.Add("bbb");
lst.Add("ccc");
IEnumerable<string>rs=lst.Where(predicate);
returnrs;
}

//基于表达式树级别的条件筛选(比如linqtoentity),表达式树只是sql语句逻辑关系的容器,最终的sql语句在表达式树被编译调用后才得到。
publicstaticIQueryable<string>Where(Expression<Func<string,bool>>predicate)
{
List<string>lst=newList<string>();
lst.Add("aaa");
lst.Add("bbb");
lst.Add("ccc");
IQueryable<string>rs=lst.AsQueryable().Where(predicate);
returnrs;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐