链式-父类中返回子类对象

  • 链式-父类中返回子类对象已关闭评论
  • 92 次浏览
  • A+
所属分类:.NET技术
摘要

一晃五年没写博客了,依旧再C#上耕耘,依旧没有啥建树,现在也不知道.net上还有多少人再使用,在这里分享一些自己觉得写的还算优雅的代码。

一晃五年没写博客了,依旧再C#上耕耘,依旧没有啥建树,现在也不知道.net上还有多少人再使用,在这里分享一些自己觉得写的还算优雅的代码。

对于自己写着完的代码,我特别喜欢链式(来源于jQuery的影响吧),大部分时候链式就是将返回值为void类型的对象,返回this指针,直到我遇到一个特殊情况——在父类中返回子类类型。大部分情况父类都不知道子类有什么,根本没有返回子类的需求

但是由于链式调用父类的接口返回父类对象,就无法继续链式了。说明可能不清楚,直接show code


 1  public class OldWhereV2<T>  2     {  3         protected Expression<Func<T, bool>> expression = null;  4   5         public OldWhereV2<T> Where(Expression<Func<T, bool>> memberExpression)  6         {  7             return this;  8         }  9  10         public OldWhereV2<T> Or(Expression<Func<T, bool>> memberExpression) 11         { 12             return this; 13         } 14  15         public OldWhereV2<T> Add(Expression<Func<T, bool>> memberExpression) 16         { 17             return this; 18         } 19     } 20  21     public class OldQeuryV2<T> : OldWhereV2<T> 22     { 23  24         public OldQeuryV2<T> Select(Expression<Func<T, object>> memberExpression) 25         { 26             return this; 27         } 28  29         public OldQeuryV2<T> Take(int count) 30         { 31             return this; 32         } 33  34         public OldQeuryV2<T> Order(Expression<Func<T, object>> memberExpression, bool asc) 35         { 36             return this; 37         } 38     }

调用的时候,如果使用链式


1  var query =new OldQeuryV2<Train>() 2                .Select(x => x.Apply_Time) 3                .Select(x => x.Apply_Time) 4                .Select(x => x.Approval_OrgName) 5                .Where(x => x.Create_Time > DateTime.Now) 6                .Add(x => x.Approval_OrgName == "") 7                .Order(x => x.Approval_OrgGID, true) 8                .Order(x => x.Apply_Time, false) 9                .Take(10);


 .Order(x => x.Approval_OrgGID, true) 这行代码会报错的。因为Where返回的是OldWhereV2<T>类型,而Order方法要求OldQeuryV2<T>类型

 这个问题困扰我一晚,后来我记得在哪里看过一本书,书中有泛型自包含的例子,但是当时完全看不懂,但是此处感觉使用完全没毛病所以就做了简单修改

 1  public abstract class Condition<T, M> where M : Condition<T, M>  2     {  3         protected Expression<Func<T, bool>> expression = null;  4   5         public M Where(Expression<Func<T, bool>> memberExpression)  6         {  7             expression = memberExpression;  8             return (M)this;  9         } 10  11         public M Or(Expression<Func<T, bool>> memberExpression) 12         { 13             if (expression == null) 14             { 15                 expression = memberExpression; 16             } 17             else 18             { 19                 var invokedExpr = Expression.Invoke(memberExpression, expression.Parameters.Cast<Expression>()); 20                 expression = Expression.Lambda<Func<T, bool>>(Expression.OrElse(expression.Body, invokedExpr), expression.Parameters); 21             } 22             return (M)this; 23         } 24  25         public M Add(Expression<Func<T, bool>> memberExpression) 26         { 27             if (expression == null) 28             { 29                 expression = memberExpression; 30             } 31             else 32             { 33                 var invokedExpr = Expression.Invoke(memberExpression, expression.Parameters.Cast<Expression>()); 34                 expression = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expression.Body, invokedExpr), expression.Parameters); 35             } 36             return (M)this; 37         } 38     } 39  40     public class Qeury<T> : Condition<T, Qeury<T>> 41     { 42         List<MemberInfo> selects = new List<MemberInfo>(); 43         Dictionary<MemberInfo, bool> orders = new Dictionary<MemberInfo, bool>(); 44         int count = 1000; 45  46         public Qeury<T> Select(Expression<Func<T, object>> memberExpression) 47         { 48             MemberInfo memberInfo = memberExpression.GetMemberInfo(); 49             if (!selects.Contains(memberInfo)) 50             { 51                 selects.Add(memberInfo); 52             } 53             return this; 54         } 55  56         public Qeury<T> Take(int count) 57         { 58             this.count = count; 59             return this; 60         } 61  62         public Qeury<T> Order(Expression<Func<T, object>> memberExpression, bool asc) 63         { 64             MemberInfo memberInfo = memberExpression.GetMemberInfo(); 65             if (orders.ContainsKey(memberInfo)) 66             { 67                 orders[memberInfo] = asc; 68             } 69             else 70             { 71                 orders.Add(memberInfo, asc); 72             } 73             return this; 74         } 75  76         public string QeurySql() 77         { 78             var queryInfo = new QueryInfo() 79             { 80                 WhereExpression = this.expression, 81                 SelectFields = this.selects, 82                 Orders = this.orders, 83                 Count = this.count 84             }; 85  86             return TableAnalysis.GetTableInfo(typeof(T)).QeurySql(queryInfo); 87         } 88     }

这里将Condition<T>类修改为Condition<T,M> 而M是Condition<T,M>的子类,返回的时候只需要返回M类型就好了,当然由于Condition返回了子类,所以我把它设置成了抽象类,但是也可以不用。由于Qeury<T> :实现了Condition<T, Qeury<T>>,所以子类就可以正常调用父类的方法了。

具体例子如下:

1 var query =new Qeury<Train>() 2                .Select(x => x.Apply_Time) 3                .Select(x => x.Apply_Time) 4                .Select(x => x.Approval_OrgName) 5                .Where(x => x.Create_Time > DateTime.Now) 6                .Add(x => x.Approval_OrgName == "") 7                .Order(x => x.Approval_OrgGID, true) 8                .Order(x => x.Apply_Time, false) 9                .Take(10);

这个算是奇技淫巧,发出来给大家看看,不过不链式不久没有烦恼了吗,正常如下面定义就好了

链式-父类中返回子类对象链式-父类中返回子类对象

 1     public class OldCondition<T>  2     {  3         public void Where(Expression<Func<T, bool>> memberExpression)  4         {  5   6         }  7   8         public void Or(Expression<Func<T, bool>> memberExpression)  9         { 10  11         } 12  13         public void Add(Expression<Func<T, bool>> memberExpression) 14         { 15  16         } 17     } 18  19     public class OldQeury<T> : OldCondition<T> 20     { 21         public void Select(Expression<Func<T, object>> memberExpression) 22         { 23  24         } 25  26         public void Take(int count) 27         { 28  29         } 30  31         public void Order(Expression<Func<T, object>> memberExpression, bool asc) 32         { 33  34         } 35     }

View Code