鏈式-父類別中返回子類物件

2023-05-18 21:00:54

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