前言:前几天写了一篇动态Lamada的文章C#进阶系列——动态Lamada,受园友xiao99的启发,今天打算来重新优化下这个动态Lamada的工具类。在此做个笔记,以免以后忘了。
一、原理分析
上篇里面我们说了动态Lamada的使用必要性以及使用场景,但是感觉用在项目里面还不太方便,最难用的就是需要传递属性名称的字符串,感觉这有点太lower了。然后就是那个枚举的使用着实感觉没啥必要,我们只需要将Contains、Equal、LessThan、GreaterThan等方法分别封装一个独立的方法即可。好了,多说容易让人头晕,直接上代码吧。
二、代码示例
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"); }
//只读属性,返回生成的Lamada public Expression<Func<Dto, bool>> Lamada {
get { return GetLambda(); } } /// <summary> /// 字符串Contains筛选 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void Contains(Expression<Func<Dto, string>> expProperty, object strValue) { Expression expRes = Expression.Call(expProperty.Body, typeof(string).GetMethod("Contains"), Expression.Constant(strValue)); m_lstExpression.Add(expRes); } /// <summary> /// 等于 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void Equal(Expression<Func<Dto, object>> expProperty, object strValue) { var member = GetMemberExpression(expProperty); Expression expRes = Expression.Equal(member, Expression.Constant(strValue, member.Type)); m_lstExpression.Add(expRes); } /// <summary> /// 小于 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void LessThan(Expression<Func<Dto, object>> expProperty, object strValue) { var member = GetMemberExpression(expProperty); Expression expRes = Expression.LessThan(member, Expression.Constant( strValue, member.Type)); m_lstExpression.Add(expRes); } /// <summary> /// 小于等于 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void LessThanOrEqual(Expression<Func<Dto, object>> expProperty, object strValue) { var member = GetMemberExpression(expProperty); Expression expRes = Expression.LessThanOrEqual(member, Expression.Constant(strValue, member.Type)); m_lstExpression.Add(expRes); } /// <summary> /// 大于 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void GreaterThan(Expression<Func<Dto, object>> expProperty, object strValue) { var member = GetMemberExpression(expProperty); Expression expRes = Expression.GreaterThan(member, Expression.Constant(strValue, member.Type)); m_lstExpression.Add(expRes); } /// <summary> /// 大于等于 /// </summary> /// <param name="expProperty"></param> /// <param name="strValue"></param> public void GreaterThanOrEqual(Expression<Func<Dto, object>> expProperty, object strValue) { var member = GetMemberExpression(expProperty); Expression expRes = Expression.GreaterThanOrEqual(member, Expression.Constant(strValue, member.Type)); m_lstExpression.Add(expRes); }private 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); } //得到MemberExpression private MemberExpression GetMemberExpression(Expression<Func<Dto, object>> exp) { var arrSplit = exp.Body.ToString().Split("(.)".ToCharArray(), StringSplitOptions.RemoveEmptyEntries); var strProperty = arrSplit[arrSplit.Length - 1]; MemberExpression member = Expression.PropertyOrField(m_Parameter, strProperty); return member; } }
可以看出,对于常用的操作我们封装了Contains、Equal、LessThan、LessThanOrEqual、GreaterThan、GreaterThanOrEqual六个方法,除了Contains方法的参数直接使用了Expression<Func<DTO, string>>类型以为,其他都用的Expression<Func<DTO, object>>。因为Contains方法只可能是string类型的变量操作,而其他操作可能涉及其他类型,就是为了传这个object类型,有个问题博主调试了很久,由于传过来的是object,这个要得到属性的真是类型貌似不那么容易了,找了很久都没找到。最后只能通过GetMemberExpression这个方法来得到MemberExpression。
还是来看看如何使用:
public object GetUsers(int limit, int offset, string username, string fullname) { var oLamadaExtention = new LamadaExtention<DTO_TR_SYS_USERS>(); oLamadaExtention.Equal(x => x.USER_NAME, username); oLamadaExtention.LessThan(x => x.MODIFYTIME, DateTime.Now); var lstRes = UserManager.Find(oLamadaExtention.lamada).ToList(); }
最大的方便就是我们想要筛选的字段可以通过lamada点出来了,再看看之前的那种用法
oLamadaExtention.GetExpression("USER_NAME", username, ExpressionType.Contains);
有没有瞬间高大上。USER_NAME直接点出来,比敲字符串要爽吧。感谢神奇的Lamada,感谢全能的C#,感谢热心的园友。