一晃五年沒寫部落格了,依舊再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 }