-
链式-父类中返回子类对象
一晃五年没写博客了,依旧再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 }
出处:https://www.cnblogs.com/watermoon2/p/17412967.html
最新更新
Objective-C语法之代码块(block)的使用
VB.NET eBook
Add-in and Automation Development In VB.NET 2003 (F
Add-in and Automation Development In VB.NET 2003 (8
Add-in and Automation Development in VB.NET 2003 (6
Add-in and Automation Development In VB.NET 2003 (5
AddIn Automation Development In VB.NET 2003 (4)
AddIn And Automation Development In VB.NET 2003 (2)
Addin and Automation Development In VB.NET 2003 (3)
AddIn And Automation Development In VB.NET 2003 (1)
2个场景实例讲解GaussDB(DWS)基表统计信息估
常用的 SQL Server 关键字及其含义
动手分析SQL Server中的事务中使用的锁
openGauss内核分析:SQL by pass & 经典执行
一招教你如何高效批量导入与更新数据
天天写SQL,这些神奇的特性你知道吗?
openGauss内核分析:执行计划生成
[IM002]Navicat ODBC驱动器管理器 未发现数据
初入Sql Server 之 存储过程的简单使用
SQL Server -- 解决存储过程传入参数作为s
武装你的WEBAPI-OData入门
武装你的WEBAPI-OData便捷查询
武装你的WEBAPI-OData分页查询
武装你的WEBAPI-OData资源更新Delta
5. 武装你的WEBAPI-OData使用Endpoint 05-09
武装你的WEBAPI-OData之API版本管理
武装你的WEBAPI-OData常见问题
武装你的WEBAPI-OData聚合查询
OData WebAPI实践-OData与EDM
OData WebAPI实践-Non-EDM模式