前言:前幾天寫了一篇動態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#,感謝熱心的園友。