动态lamada1.docx
《动态lamada1.docx》由会员分享,可在线阅读,更多相关《动态lamada1.docx(6页珍藏版)》请在冰豆网上搜索。
动态lamada1
动态lamada
(1)
前言:
在DDD系列文章里面,我们在后台仓储里面封装了传递Lamada表达式的通用方法,类似这样:
publicvirtualIQueryableFind(Expressionbool>>express){Funcbool>lamada=express.Compile();returnUnitOfWork.context.Set().Where(lamada).AsQueryable();}通过前端传过来的Lamada表达式,直接放到Where条件里面查询。
那么问题来了,我们前端如何传入Lamada呢?
当然,有人说了,这个不用传啊,前端直接.Find(x=>x.Name==”abc”)这样写就好了啊。
确实,如果前端条件只有一个条件,你确实可以这样简单处理,但是实际开发的过程中,我们很多时候是需要传递多个参数,并且.Find(x=>x.Name==”abc”)这种写法也不利于方法的封装。
于是,我们神奇的动态Lamada诞生了。
一、再谈Lamada表达式
1、匿名委托
之前在介绍委托的时候我们介绍过一种特殊的匿名委托,它型如:
classProgram{privatedelegatevoidSayHello(stringname);staticvoidMain(string[]args){Say('张三',delegate(stringname){Console.WriteLine('你好,'+name);});Say('Zhangsan',delegate(stringname){Console.WriteLine('Hello,'+name);});}staticvoidSay(stringname,SayHellodTest){dTest(name);}}
也就是说,不用定义一种具体的委托方法去对应SayHello(stringname);,而直接delegate(stringname){}这样定义一种匿名的委托去执行,这样能减少部分定义具体方法的代码。
2、Lamada表达式进化史
了解了匿名委托的概念,我们来看看我们经常使用的Linq里面的扩展方法Where、Select等。
先来看看一般用法:
varlstTest=newListstring>();//.......业务逻辑varlstRes=lstTest.Where(x=>x.Contains('_'));
我们来将Where里面的x=>x.Contains(“_”)分解。
初级进化(最原始的匿名委托形式):
Funcstring,bool>oFunc=delegate(stringx){returnx.Contains('_');};lstRes=lstTest.Where(oFunc);
高级进化(型如Lamada,但还有匿名委托的影子):
Funcstring,bool>oFunc=(stringx)=>{returnx.Contains('_');};lstRes=lstTest.Where(oFunc);
究极进化(完完全全的Lamada)
Funcstring,bool>oFunc=x=>x.Contains('_');lstRes=lstTest.Where(oFunc);
有没有很强大,是不是一样一样的。
其实这样一看lamada就是匿名委托的缩略形式。
x=>x.Contains(“_”)表达式左边的表示Func里面的string类型变量,x.Contains(“_”)表示bool类型的返回值。
有了这份进化史,程序员再也不用担心面试官问我Lamada怎么回事了。
二、动态Lamada
与其叫动态Lamada,更加严谨一点应该叫动态Expression,因为拼接Lamada表达式用的基本都是Expression的类和方法。
博主习惯,暂且就叫它动态Lamada吧。
publicclassDTO_ORDER{publicstringTO_ORDER_ID{get;set;}publicstringORDER_NO{get;set;}publicstringORDER_NAME{get;set;}publicintORDER_STATUS{get;set;}}staticvoidMain(){//1.定义lamada的参数,型如我们常写的“x=>”ParameterExpressionm_Parameter=Expression.Parameter(typeof(DTO_ORDER),'x');//2.定义要使用lamada的属性成员(比如我们这里要对DTO_ORDER对象的ORDER_NO属性做筛选)MemberExpressionmember=Expression.PropertyOrField(m_Parameter,'ORDER_NO');//3.定义筛选的操作(是大于、等于、小于、like等)ExpressionexpRes=Expression.Equal(member,Expression.Constant('aaaa',member.Type));//4.将表达式转换为Lamada的表达式Expressionbool>>exprelamada=Expression.Lambdabool>>(expRes,m_Parameter);varlstRes=newList();for(vari=0;i10;i++){varoModel=newDTO_ORDER();oModel.ORDER_NO=i%2==0?
'aaaa':
'bbbb';lstRes.Add(oModel);}//5.将Expression表达式转换为Func委托,用于Where里面的参数varlamada=exprelamada.Compile();lstRes=lstRes.Where(lamada).ToList();}
以上就构造了一个查询List对象里面ORDER_NO属性等于aaaa的lamada表达式。
我们看看运行效果截图:
是不是已经得到了我们想要的表达式!
有没有很简单。
。
。
三、动态Lamada的使用
看到这里有人就郁闷了,为了得到x=>x.ORDER_NO==”aaaa”这种表达式,你绕了这么大一圈,有什么屌用?
直接lstRes=lstRes.Where(x=>x.ORDER_NO==”aaaa”);就能够搞定的事,你非要把简单问题复杂化。
其实不然,有一定编程经验的朋友肯定知道,一般我们前端传过来的查询参数肯定不会只有一个,当需要查询多个参数时需要我们构造一个统一的Lamada传递到后台;当然你也可以说,我将多个参数全部传递到后台,然后再后台使用IQueryable接口去过滤。
当然,这确实可行,但是别忘了我们封装Find(Expressionexp…)的意义,不就是为了简化方法么,从这点来说,构造动态Lamada非常必要。
1、通用Lamada表达式类
博主封装了一个简单操作(大于、等于、小于、like等)的动态Lamada类。
publicclassLamadaExtentionwhereDto:
new(){privateListm_lstExpression=null;privateParameterExpressionm_Parameter=null;publicLamadaExtention(){m_lstExpression=newList();m_Parameter=Expression.Parameter(typeof(Dto),'x');} //构造表达式,存放到m_lstExpression集合里面publicvoidGetExpression(stringstrPropertyName,objectstrValue,ExpressionTypeexpressType){ExpressionexpRes=null;MemberExpressionmember=Expression.PropertyOrField(m_Parameter,strPropertyName);if(expressType==ExpressionType.Contains){expRes=Expression.Call(member,typeof(string).GetMethod('Contains'),Expression.Constant(strValue));}elseif(expressType==ExpressionType.Equal){expRes=Expression.Equal(member,Expression.Constant(strValue,member.Type));}elseif(expressType==ExpressionType.LessThan){expRes=Expression.LessThan(member,Expression.Constant(strValue,member.Type));}elseif(expressType==ExpressionType.LessThanOrEqual){expRes=Expression.LessThanOrEqual(member,Expression.Constant(strValue,member.Type));}elseif(expressType==ExpressionType.GreaterThan){expRes=Expression.GreaterThan(member,Expression.Constant(strValue,member.Type));}elseif(expressType==ExpressionType.GreaterThanOrEqual){expRes=Expression.GreaterThanOrEqual(member,Expression.Constant(strValue,member.Type));}//returnexpRes;m_lstExpression.Add(expRes);}//针对Or条件的表达式publicvoidGetExpression(stringstrPropertyName,Listobject>lstValue){ExpressionexpRes=null;MemberExpressionmember=Expression.PropertyOrField(m_Parameter,strPropertyName);foreach(varoValueinlstValue){if(expRes==null){expRes=Expression.Equal(member,Expression.Constant(oValue,member.Type));}else{expRes=Expression.Or(expRes,Expression.Equal(member,Expression.Constant(oValue,member.Type)));}}m_lstExpression.Add(expRes);} //得到Lamada表达式的Expression对象publicExpressionbool>>GetLambda(){ExpressionwhereExpr=null;foreach(varexprinthis.m_lstExpression){if(whereExpr==null)whereExpr=expr;elsewhereExpr=Expression.And(whereExpr,expr);}if(whereExpr==null)returnnull;returnExpression.Lambda>(whereExpr,m_Parameter);}}//用于区分操作的枚举publicenumExpressionType{Contains,//likeEqual,//等于LessThan,//小于LessThanOrEqual,//小于等于GreaterThan,//大于GreaterThanOrEqual//大于等于}
2、使用场景
博主项目中有某一个页面,查询条件非常多,需要传递到后台很多参数。
先来看看页面:
来看后台webapi代码
publicobjectGet(intlimit,intoffset,stringstrBodyno,stringstrVin,stringstrOrderno,stringstrEngincode,stringstrOrderstatus,stringstrTranscode,stringstrVms,stringstrCarcode,stringstrImportStartdate,stringstrImportEnddate,stringstrSendStartdate,stringstrSendEnddate){//1.定义对象,传入泛型varoLamadaExtention=newLamadaExtention();//2.依次构造Lamada表达式if(!
string.IsNullOrEmpty(strBodyno)){oLamadaExtention.GetExpression('BODY_NO',strBodyno,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strVin)){oLamadaExtention.GetExpression('VIN',strVin,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strOrderno)){oLamadaExtention.GetExpression('ORDER_NO',strOrderno,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strEngincode)){oLamadaExtention.GetExpression('ENGIN_CODE',strEngincode,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strOrderstatus)){if(strOrderstatus.Contains(',')){varlstValue=strOrderstatus.Split(','.ToCharArray(),StringSplitOptions.RemoveEmptyEntries).ToList();varlstObj=newListobject>();lstValue.ForEach(x=>{lstObj.Add(Convert.ToInt16(x));});oLamadaExtention.GetExpression('ORDER_STATUS',lstObj);}else{oLamadaExtention.GetExpression('ORDER_STATUS',Convert.ToInt16(strOrderstatus),ExpressionType.Equal);}}if(!
string.IsNullOrEmpty(strTranscode)){oLamadaExtention.GetExpression('TRANS_CODE',strTranscode,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strVms)){oLamadaExtention.GetExpression('VMS_NO',strVms,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strCarcode)){oLamadaExtention.GetExpression('TM_MODEL_MATERIAL_ID',strCarcode,ExpressionType.Contains);}if(!
string.IsNullOrEmpty(strImportStartdate)){oLamadaExtention.GetExpression('CREATE_DATE',Convert.ToDateTime(strImportStartdate),ExpressionType.GreaterThanOrEqual);}if(!
string.IsNullOrEmpty(strImportEnddate)){oLamadaExtention.GetExpression('CREATE_DATE',Convert.ToDateTime(strImportEnddate),ExpressionType.LessThanOrEqual);}if(!
string.IsNullOrEmpty(strSendStartdate)){oLamadaExtention.GetExpression('OFFLINE_DATE_ACT',Convert.ToDateTime(strSendStartdate),ExpressionType.GreaterThanOrEqual);}if(!
string.IsNullOrEmpty(strSendEnddate)){oLamadaExtention.GetExpression('OFFLINE_DATE_ACT',Convert.ToDateTime(strSendEnddate),ExpressionType.LessThanOrEqual);}//3.得到需要的Lamada表达式Expressionvarlamada=oLamadaExtention.GetLambda();varlstRes=orderManager.Find(lamada).ToList();//4.得到BootstrapTable需要的对象varoRes=newPageRowData(); returnoRes;;}
仓储基类里面的find方法:
publicvirtualIQueryableFind(Expressionbool>>express){Funcbool>lamada=express.Compile();returnUnitOfWork.context.Set().Where(lamada).AsQueryable();}
四、小结
至此,所谓的动态Lamada就完了。
如果你之前用过,请一笑而过;当然如果你没用过,学习点新东西也是好的。
请不要嘲笑博主乱下定义,叫动态Lamada挺好的呢。
当然你可以叫动态Expression,动态Linq都行,不管叫什么,正确使用才是王道。