前言:在DDD系列文章里面,我们在后台仓储里面封装了传递Lamada表达式的通用方法,类似这样:

     public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express)
{
Func<TEntity, bool> lamada = express.Compile();
return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>();
}

通过前端传过来的Lamada表达式,直接放到Where条件里面查询。那么问题来了,我们前端如何传入Lamada呢?当然,有人说了,这个不用传啊,前端直接.Find(x=>x.Name=="abc")这样写就好了啊。确实,如果前端条件只有一个条件,你确实可以这样简单处理,但是实际开发的过程中,我们很多时候是需要传递多个参数,并且.Find(x=>x.Name=="abc")这种写法也不利于方法的封装。于是,我们神奇的动态Lamada诞生了。

一、再谈Lamada表达式

1、匿名委托

之前在介绍委托的时候我们介绍过一种特殊的匿名委托,它型如:

    class Program
{
private delegate void SayHello(string name);
static void Main(string[] args)
{
Say("张三", delegate(string name)
{
Console.WriteLine("你好," + name);
});
Say("Zhangsan", delegate(string name)
{
Console.WriteLine("Hello," + name);
});
}
static void Say(string name,SayHello dTest)
{
dTest(name);
}
}

也就是说,不用定义一种具体的委托方法去对应SayHello(string name);,而直接delegate(string name){}这样定义一种匿名的委托去执行,这样能减少部分定义具体方法的代码。

2、Lamada表达式进化史

了解了匿名委托的概念,我们来看看我们经常使用的Linq里面的扩展方法Where、Select等。先来看看一般用法:

var lstTest = new List<string>();
//.......业务逻辑
var lstRes = lstTest.Where(x => x.Contains("_"));

我们来将Where里面的x => x.Contains("_")分解。

初级进化(最原始的匿名委托形式):

Func<string, bool> oFunc = delegate(string x) { return x.Contains("_"); };
lstRes = lstTest.Where(oFunc);

高级进化(型如Lamada,但还有匿名委托的影子):

Func<string, bool> oFunc = (string x) => { return x.Contains("_"); };
lstRes = lstTest.Where(oFunc);

究极进化(完完全全的Lamada)

Func<string, 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吧。废话不多说,直接吃点栗子吧。

  public class DTO_ORDER
{
public string TO_ORDER_ID { get; set; }
public string ORDER_NO { get; set; }
public string ORDER_NAME { get; set; }
public int ORDER_STATUS {get;set;}
}
    static void Main()
{
//1.定义lamada的参数,型如我们常写的“x=>”
ParameterExpression m_Parameter = Expression.Parameter(typeof(DTO_ORDER), "x"); //2.定义要使用lamada的属性成员(比如我们这里要对DTO_ORDER对象的ORDER_NO属性做筛选)
MemberExpression member = Expression.PropertyOrField(m_Parameter, "ORDER_NO"); //3.定义筛选的操作(是大于、等于、小于、like等)
Expression expRes = Expression.Equal(member, Expression.Constant("aaaa", member.Type)); //4.将表达式转换为Lamada的表达式
Expression<Func<DTO_ORDER, bool>> exprelamada = Expression.Lambda<Func<DTO_ORDER, bool>>(expRes, m_Parameter); var lstRes = new List<DTO_ORDER>();
for (var i = ; i < ; i++)
{
var oModel = new DTO_ORDER();
oModel.ORDER_NO = i % == ? "aaaa" : "bbbb";
lstRes.Add(oModel);
}
//5.将Expression表达式转换为Func委托,用于Where里面的参数
var lamada = exprelamada.Compile();
lstRes = lstRes.Where(lamada).ToList();
    }

以上就构造了一个查询List<DTO_ORDER>对象里面ORDER_NO 属性等于aaaa的lamada表达式。我们看看运行效果截图:

是不是已经得到了我们想要的表达式!有没有很简单。。。

三、动态Lamada的使用

看到这里有人就郁闷了,为了得到x=>x.ORDER_NO=="aaaa"这种表达式,你绕了这么大一圈,有什么屌用?直接lstRes=lstRes.Where(x=>x.ORDER_NO=="aaaa");就能够搞定的事,你非要把简单问题复杂化。其实不然,有一定编程经验的朋友肯定知道,一般我们前端传过来的查询参数肯定不会只有一个,当需要查询多个参数时需要我们构造一个统一的Lamada传递到后台;当然你也可以说,我将多个参数全部传递到后台,然后再后台使用IQueryable接口去过滤。当然,这确实可行,但是别忘了我们封装Find(Expression exp...)的意义,不就是为了简化方法么,从这点来说,构造动态Lamada非常必要。

1、通用Lamada表达式类

博主封装了一个简单操作(大于、等于、小于、like等)的动态Lamada类。

  public class LamadaExtention<Dto> where Dto:new ()
{
private List<Expression> m_lstExpression = null;
private ParameterExpression m_Parameter = null; public LamadaExtention()
{
m_lstExpression = new List<Expression>();
m_Parameter = Expression.Parameter(typeof(Dto), "x");
}
     //构造表达式,存放到m_lstExpression集合里面
public void GetExpression(string strPropertyName, object strValue, ExpressionType expressType)
{
Expression expRes = null;
MemberExpression member = Expression.PropertyOrField(m_Parameter, strPropertyName);
if (expressType == ExpressionType.Contains)
{
expRes = Expression.Call(member, typeof(string).GetMethod("Contains"), Expression.Constant(strValue));
}
else if (expressType == ExpressionType.Equal)
{
expRes = Expression.Equal(member, Expression.Constant(strValue, member.Type));
}
else if (expressType == ExpressionType.LessThan)
{
expRes = Expression.LessThan(member, Expression.Constant(strValue, member.Type));
}
else if (expressType == ExpressionType.LessThanOrEqual)
{
expRes = Expression.LessThanOrEqual(member, Expression.Constant(strValue, member.Type));
}
else if (expressType == ExpressionType.GreaterThan)
{
expRes = Expression.GreaterThan(member, Expression.Constant(strValue, member.Type));
}
else if (expressType == ExpressionType.GreaterThanOrEqual)
{
expRes = Expression.GreaterThanOrEqual(member, Expression.Constant(strValue, member.Type));
}
//return expRes;
m_lstExpression.Add(expRes);
} //针对Or条件的表达式
public void GetExpression(string strPropertyName, List<object> lstValue)
{
Expression expRes = null;
MemberExpression member = Expression.PropertyOrField(m_Parameter, strPropertyName);
foreach (var oValue in lstValue)
{
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对象
public Expression<Func<Dto, bool>> GetLambda()
{
Expression whereExpr = null;
foreach (var expr in this.m_lstExpression)
{
if (whereExpr == null) whereExpr = expr;
else whereExpr = Expression.And(whereExpr, expr);
}
if (whereExpr == null)
return null;
return Expression.Lambda<Func<Dto, Boolean>>(whereExpr, m_Parameter);
}
}

   //用于区分操作的枚举
public enum ExpressionType
{
Contains,//like
Equal,//等于
LessThan,//小于
LessThanOrEqual,//小于等于
GreaterThan,//大于
GreaterThanOrEqual//大于等于
}

2、使用场景

博主项目中有某一个页面,查询条件非常多,需要传递到后台很多参数。先来看看页面:

来看后台web api代码

public object Get(int limit, int offset, string strBodyno, string strVin, string strOrderno, string strEngincode,
string strOrderstatus, string strTranscode, string strVms, string strCarcode,
string strImportStartdate, string strImportEnddate, string strSendStartdate, string strSendEnddate)
{
//1.定义对象,传入泛型
var oLamadaExtention = new LamadaExtention<DTO_TO_ORDER>(); //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(","))
{
var lstValue = strOrderstatus.Split(",".ToCharArray(), StringSplitOptions.RemoveEmptyEntries).ToList();
var lstObj = new List<object>();
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表达式Expression
var lamada = oLamadaExtention.GetLambda();
var lstRes = orderManager.Find(lamada).ToList(); //4.得到Bootstrap Table需要的对象
var oRes = new PageRowData();
       return oRes; ;
}

仓储基类里面的find方法:

     public virtual IQueryable<TEntity> Find(Expression<Func<TEntity, bool>> express)
{
Func<TEntity, bool> lamada = express.Compile();
return UnitOfWork.context.Set<TEntity>().Where(lamada).AsQueryable<TEntity>();
}

四、小结

至此,所谓的动态Lamada就完了。如果你之前用过,请一笑而过;当然如果你没用过,学习点新东西也是好的。请不要嘲笑博主乱下定义,叫动态Lamada挺好的呢。当然你可以叫动态Expression,动态Linq都行,不管叫什么,正确使用才是王道。

C#进阶系列——动态Lamada的更多相关文章

  1. C#进阶系列——动态Lamada(二:优化)

    前言:前几天写了一篇动态Lamada的文章C#进阶系列——动态Lamada,受园友xiao99的启发,今天打算来重新优化下这个动态Lamada的工具类.在此做个笔记,以免以后忘了. 一.原理分析 上篇 ...

  2. 【转载】C#进阶系列——动态Lamada(二:优化)

    前言:前几天写了一篇动态Lamada的文章C#进阶系列——动态Lamada,受园友xiao99的启发,今天打算来重新优化下这个动态Lamada的工具类.在此做个笔记,以免以后忘了. 一.原理分析 上篇 ...

  3. 【转载】C#进阶系列——动态Lamada

    前言:在DDD系列文章里面,我们在后台仓储里面封装了传递Lamada表达式的通用方法,类似这样: public virtual IQueryable<TEntity> Find(Expre ...

  4. C#进阶系列——DDD领域驱动设计初探(七):Web层的搭建

    前言:好久没更新博客了,每天被该死的业务缠身,今天正好一个模块完成了,继续来完善我们的代码.之前的六篇完成了领域层.应用层.以及基础结构层的部分代码,这篇打算搭建下UI层的代码. DDD领域驱动设计初 ...

  5. C#进阶系列——WebApi 接口参数不再困惑:传参详解

    前言:还记得刚使用WebApi那会儿,被它的传参机制折腾了好久,查阅了半天资料.如今,使用WebApi也有段时间了,今天就记录下API接口传参的一些方式方法,算是一个笔记,也希望能帮初学者少走弯路.本 ...

  6. C#进阶系列——WebApi 路由机制剖析:你准备好了吗?

    前言:从MVC到WebApi,路由机制一直是伴随着这些技术的一个重要组成部分. 它可以很简单:如果你仅仅只需要会用一些简单的路由,如/Home/Index,那么你只需要配置一个默认路由就能简单搞定: ...

  7. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper(三:附源码)

    前言:之前的两篇封装了一些基础的表单组件,这篇继续来封装几个基于bootstrap的其他组件.和上篇不同的是,这篇的有几个组件需要某些js文件的支持. 本文原创地址:http://www.cnblog ...

  8. C#进阶系列——一步一步封装自己的HtmlHelper组件:BootstrapHelper

    前言:之前学习过很多的Bootstrap组件,博主就在脑海里构思:是否可以封装一套自己Bootstrap组件库呢.再加上看到MVC的Razor语法里面直接通过后台方法输出前端控件的方式,于是打算仿照H ...

  9. C#进阶系列——DDD领域驱动设计初探(三):仓储Repository(下)

    前言:上篇介绍了下仓储的代码架构示例以及简单分析了仓储了使用优势.本章还是继续来完善下仓储的设计.上章说了,仓储的最主要作用的分离领域层和具体的技术架构,使得领域层更加专注领域逻辑.那么涉及到具体的实 ...

随机推荐

  1. 提交留言HTML模板代码

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <t ...

  2. SharePoint 2013 定制搜索显示模板(二)

    前言 之前一篇博客,简单的介绍了如何定制搜索显示模板,这一次,我们介绍一下如何定制搜索显示时,弹出来的那个页面,相信这个大家也都会遇到的. 1.第一部分就是搜索显示模板的部分,第二部分就是搜索项目详情 ...

  3. 赞一个 kindle电子书有最新的计算机图书可买了【Docker技术入门与实战】

    最近对docker这个比较感兴趣,找一个比较完整的书籍看看,在z.cn上找到了电子书,jd dangdang看来要加油啊 Docker技术入门与实战 [Kindle电子书] ~ 杨保华 戴王剑 曹亚仑 ...

  4. Android高效计算——RenderScript(一)

    高效计算——RenderScript RenderScript是安卓平台上很受谷歌推荐的一个高效计算平台,它能够自动把计算任务分配到各个可用的计算核心上,包括CPU,GPU以及DSP等,提供十分高效的 ...

  5. 安装免费的正版Windows10操作系统 - 初学者系列 - 学习者系列文章

    Windows 10操作系统是目前Windows平台最新的操作系统,其相对于其它旧版的操作系统是一个比较成功的操作系统.微软直接使用10版本号,跳过了9版本号进行发布这款操作系统,说明windows ...

  6. HADOOP安装指南-Ubuntu15.10和hadoop2.7.2

    Ubuntu15.10中安装hadoop2.7.2安装手册 太初 目录 1.      Hadoop单点模式... 2 1.1        安装步骤... 2 0.环境和版本... 2 1.在ubu ...

  7. [LoadRunner]LR11安装或破解时报错的解决方法

    背景:在性能测试项目上,需要安装到LR11进行性能测试,而在安装时会出现安装运行环境失败,安装文件缺失等问题.现总结了上述问题,并给出以下解决方法: 问题1:安装LoadRunner时出现“计算机缺少 ...

  8. [Java入门笔记] Java语言基础(四):流程控制

    流程控制指的是在程序运行的过程中控制程序运行走向的方式.主要分为以下几种: 顺序结构 顺序结构,顾名思义,是指程序从上往下逐步顺序执行.中间没有任何的判断和跳转. 分支结构 Java提供两种分支结构: ...

  9. phpRedis安装、配置及简单使用

    安装phpRedis前,请先安装Redis,再安装phpRedis插件. 1.下载安装 在linux服务器上,命令行执行以下命令(cd ./usr local/src 一般源码放在这里(推荐源码安装) ...

  10. ELK+redis搭建nginx日志分析平台

    ELK+redis搭建nginx日志分析平台发表于 2015-08-19   |   分类于 Linux/Unix   |  ELK简介ELKStack即Elasticsearch + Logstas ...