C#进阶系列——动态Lamada

简介: 原文:C#进阶系列——动态Lamada前言:在DDD系列文章里面,我们在后台仓储里面封装了传递Lamada表达式的通用方法,类似这样:      public virtual IQueryable Find(Expression express) { Func lamada = express.
原文: C#进阶系列——动态Lamada

前言:在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 = 0; i < 10; i++)
            {
                var oModel = new DTO_ORDER();
                oModel.ORDER_NO = i % 2 == 0 ? "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都行,不管叫什么,正确使用才是王道。

 

目录
相关文章
|
SQL 关系型数据库 MySQL
TiDB支持的SQL语法概述
【2月更文挑战第28天】本章将对TiDB所支持的SQL语法进行概述,涵盖其主要的语法特性和功能。我们将从基本的SQL语句到更复杂的查询和操作,逐步介绍TiDB的SQL语法,帮助读者更好地理解和使用TiDB进行数据库操作。
1322 0
|
网络安全 虚拟化 Windows
同一个局域网主机中的一台主机连接另一台主机的虚拟机
同一个局域网主机中的一台主机连接另一台主机的虚拟机
|
SQL 关系型数据库 MySQL
TiDB亿级数据亚秒响应查询将MySql数据全量迁移到TiDB
TiDB亿级数据亚秒响应查询将MySql数据全量迁移到TiDB
787 0
|
7月前
|
JSON 负载均衡 监控
《服务治理》Thrift与gRPC深度对比与实践
在微服务架构中,服务间通信是系统设计的核心环节。RPC(Remote Procedure Call)框架通过抽象网络通信细节,让开发者能够像调用本地方法一样调用远程服务,极大地提升了开发效率。
|
6月前
|
人工智能 运维 安全
云栖专刊 | 深度解读阿里云网络全新能力升级,助力企业出海和AI创新
阿里云飞天洛神云网络在2025云栖大会发布全新升级,聚焦企业出海与AI创新,推出确定性网络、智能云网络及AI for Network三大能力,提升全球连接质量,构建高效、安全、智能的云网络底座。
820 8
云栖专刊 | 深度解读阿里云网络全新能力升级,助力企业出海和AI创新
|
运维 架构师 云栖大会
2024云栖大会 | 阿里云网络技术Session主题资料和视频回放归档
2024年9月19日-21日,杭州,一年一度的云栖大会如期而至;阿里云飞天洛神云网络作为阿里云计算的连接底座,是飞天云操作系统的核心组件,致力于为上云企业提供高可靠、高性能、高弹性、智能的连接服务。本次云栖,云网络产品线也带来全系列产品升级,以及创新技术重磅解读,围绕增强确定性、深度可观测、高效自动化和敏捷全球化带来技术、产品和服务升级,以及全新的生态伙伴合作构建。
1613 15
|
存储 弹性计算 安全
阿里云服务器ECS通用型规格族解析:实例规格、性能基准与场景化应用指南
作为ECS产品矩阵中的核心序列,通用型规格族以均衡的计算、内存、网络和存储性能著称,覆盖从基础应用到高性能计算的广泛场景。通用型规格族属于独享型云服务器,实例采用固定CPU调度模式,实例的每个CPU绑定到一个物理CPU超线程,实例间无CPU资源争抢,实例计算性能稳定且有严格的SLA保证,在性能上会更加稳定,高负载情况下也不会出现资源争夺现象。本文将深度解析阿里云ECS通用型规格族的技术架构、实例规格特性、最新价格政策及典型应用场景,为云计算选型提供参考。
|
新零售 供应链 数据可视化
从销售到售后:汽车经销商如何用数据工具驱动门店管理?
随着汽车市场竞争加剧,新能源车崛起和新零售模式普及,传统汽车经销商门店运营面临盈利能力下降、售后客户流失及业务管理复杂等挑战。信息化工具如项目管理软件、DMS系统、CRM系统、数据分析工具和自动化营销工具,能通过数据整合、流程优化和智能化管理,帮助经销商实现精益运营,提升竞争力。
554 2
从销售到售后:汽车经销商如何用数据工具驱动门店管理?
|
人工智能 运维 Cloud Native
重磅解读阿里云云网络领域关键技术创新
2023年10月31日,杭州·云栖大会,阿里云技术主论坛带来了一场关于阿里云主力产品与技术创新的深度解读,阿里云网络产品线负责人祝顺民带来《云智创新,网络随行》的主题发言,针对阿里云飞天洛神云网络(下文简称洛神网络)领域产品服务创新以及背后的技术积累进行了深度解读,不少背后的创新技术系首次重磅披露。
130079 16
|
Linux 开发者 Python
从Windows到Linux,Python系统调用如何让代码飞翔🚀
【9月更文挑战第10天】在编程领域,跨越不同操作系统的障碍是常见挑战。Python凭借其“编写一次,到处运行”的理念,显著简化了这一过程。通过os、subprocess、shutil等标准库模块,Python提供了统一的接口,自动处理底层差异,使代码在Windows和Linux上无缝运行。例如,`open`函数在不同系统中以相同方式操作文件,而`subprocess`模块则能一致地执行系统命令。此外,第三方库如psutil进一步增强了跨平台能力,使开发者能够轻松编写高效且易维护的代码。借助Python的强大系统调用功能,跨平台编程变得简单高效。
455 1

热门文章

最新文章