1. 程式人生 > 其它 >C# Expression建立ICollectionView的動態多重過濾條件

C# Expression建立ICollectionView的動態多重過濾條件

ICollectionView有一個Filter屬性,接受一個Predicate<object>的委託 來生成過濾檢視

準備一個實體資料類

 1 /// <summary>
 2     /// 測試資料類
 3     /// </summary>
 4     public class UserDataProxy : DynamicObject
 5     {
 6         private Dictionary<string, object> _dict = new Dictionary<string, object>();
 7 
 8
public string Color { get; set; } 9 10 public Guid Guid { get; set; } 11 12 public string Layer { get; set; } 13 14 public string Length { get; set; } 15 16 public string Name { get; set; } 17 18 public string Type { get; set; } 19 20 /// <summary>
21 /// 新增動態屬性 22 /// </summary> 23 /// <param name="propertyName"></param> 24 /// <param name="value"></param> 25 public void AddDynamicProperty(string propertyName, object value) 26 { 27 _dict[propertyName] = value; 28 }
29 30 public IEnumerable<string> GetAllProPertyNames() 31 { 32 var list = new List<string>() 33 { 34 "Guid","Type","Layer","Name","Color" 35 }; 36 list.AddRange(GetDynamicMemberNames()); 37 return list; 38 } 39 40 /// <summary> 41 /// 重寫獲取動態屬性的方法 42 /// </summary> 43 /// <returns></returns> 44 public override IEnumerable<string> GetDynamicMemberNames() 45 { 46 return _dict.Keys; 47 } 48 49 /// <summary> 50 /// 獲取動態屬性的方法 51 /// </summary> 52 /// <param name="propertyName"></param> 53 /// <returns></returns> 54 public object GetDynamicValue(string propertyName) 55 { 56 if (_dict.Keys.Contains(propertyName)) 57 { 58 return _dict[propertyName]; 59 } 60 return null; 61 } 62 63 public void RemoveDynamicProperty(string propertyName) 64 { 65 if (_dict.Keys.Contains(propertyName)) 66 { 67 _dict.Remove(propertyName); 68 } 69 } 70 71 /// <summary> 72 /// 重寫獲取動態屬性 73 /// </summary> 74 /// <param name="binder"></param> 75 /// <param name="result"></param> 76 /// <returns></returns> 77 public override bool TryGetMember(GetMemberBinder binder, out object result) 78 { 79 var key = binder.Name; 80 return _dict.TryGetValue(key, out result); 81 } 82 83 /// <summary> 84 /// 重寫設定動態屬性 85 /// </summary> 86 /// <param name="binder"></param> 87 /// <param name="value"></param> 88 /// <returns></returns> 89 public override bool TrySetMember(SetMemberBinder binder, object value) 90 { 91 var key = binder.Name; 92 _dict[key] = value ?? default; 93 return true; 94 } 95 }

準備一個運算子列舉

 1 /// <summary>
 2     /// 過濾運算子列舉
 3     /// </summary>
 4     [Flags]
 5     public enum EFilterOperator
 6     {
 7         [Description("=")]
 8         Equal = 1,
 9 
10         [Description("!=")]
11         NotEqual = 2,
12 
13         [Description(">")]
14         GreaterThan = 4,
15 
16         [Description("<")]
17         LessThan = 8,
18 
19         [Description(">=")]
20         GreaterThanOrEqual = 16,
21 
22         [Description("<=")]
23         LessThanOrEqual = 32,
24 
25         [Description("s")]
26         StartsWith = 64,
27 
28         [Description("e")]
29         EndWith = 128,
30 
31         [Description("<>")]
32         Contains = 256,
33 
34         [Description("><")]
35         NotContains = 512,
36     }

準備一個表示式樹輔助類

  1 /// <summary>
  2     /// 表示式輔助類
  3     /// </summary>
  4     public class ExpressionTreeHelper
  5     {
  6         /// <summary>
  7         /// 轉換屬性表示式 o as UserDataProxy
  8         /// </summary>
  9         /// <typeparam name="T"></typeparam>
 10         /// <param name="type"></param>
 11         /// <returns></returns>
 12         public static UnaryExpression ConvertTo<T>(ParameterExpression parameterExpression)
 13         {
 14             return Expression.TypeAs(parameterExpression, typeof(T));
 15         }
 16 
 17         /// <summary>
 18         /// 建立條件表示式 i.Name.Contains("xx")
 19         /// </summary>
 20         /// <param name="memberExpression">屬性</param>
 21         /// <param name="condition">條件</param>
 22         /// <param name="content"></param>
 23         /// <returns></returns>
 24         public static Expression CreateCondition(MemberExpression memberExpression, EFilterOperator condition, string content)
 25         {
 26             if (content == null)
 27             {
 28                 return null;
 29             }
 30             var flag = double.TryParse(content, out double num);//轉換數字 能夠轉換是數字,不能就是文字
 31 
 32             BinaryExpression exp;//二位運算子表示式
 33 
 34             Expression left;//左側表示式
 35             ConstantExpression right;//右側表示式
 36 
 37             if (flag)
 38             {
 39                 //把屬性轉換為數字 因為有的屬性可能是字串
 40                 left = Expression.Call(null, typeof(double).GetMethod("Parse", new Type[] { typeof(string) }), new Expression[] { memberExpression });
 41 
 42                 //右側的表示式
 43                 right = Expression.Constant(num, typeof(double));
 44             }
 45             else
 46             {
 47                 //把屬性轉換為字串
 48                 left = Expression.Call(memberExpression, typeof(string).GetMethod("ToString", new Type[] { }), new Expression[] { });
 49 
 50                 //右側的表示式
 51                 right = Expression.Constant(content, typeof(string));
 52             }
 53 
 54             MethodCallExpression callExp;
 55             switch (condition)
 56             {
 57                 case EFilterOperator.Equal:
 58                     if (!flag)
 59                     {
 60                         return null;
 61                     }
 62                     exp = Expression.Equal(left, right);
 63                     return exp;
 64 
 65                 case EFilterOperator.NotEqual:
 66                     if (!flag)
 67                     {
 68                         return null;
 69                     }
 70                     exp = Expression.NotEqual(left, right);
 71 
 72                     return exp;
 73 
 74                 case EFilterOperator.GreaterThan:
 75                     if (!flag)
 76                     {
 77                         return null;
 78                     }
 79                     exp = Expression.GreaterThan(left, right);
 80 
 81                     return exp;
 82 
 83                 case EFilterOperator.LessThan:
 84                     if (!flag)
 85                     {
 86                         return null;
 87                     }
 88                     exp = Expression.LessThan(left, right);
 89 
 90                     return exp;
 91 
 92                 case EFilterOperator.GreaterThanOrEqual:
 93                     if (!flag)
 94                     {
 95                         return null;
 96                     }
 97                     exp = Expression.GreaterThanOrEqual(left, right);
 98 
 99                     return exp;
100 
101                 case EFilterOperator.LessThanOrEqual:
102                     if (!flag)
103                     {
104                         return null;
105                     }
106                     exp = Expression.LessThanOrEqual(left, right);
107 
108                     return exp;
109 
110                 case EFilterOperator.StartsWith:
111                     callExp = Expression.Call(left, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), new Expression[] { right });
112 
113                     return callExp;
114 
115                 case EFilterOperator.EndWith:
116                     callExp = Expression.Call(left, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), new Expression[] { right });
117                     return callExp;
118 
119                 case EFilterOperator.Contains:
120 
121                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
122 
123                     return callExp;
124 
125                 case EFilterOperator.NotContains:
126                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
127                     var not = Expression.Not(callExp);//取反
128 
129                     return not;
130             };
131 
132             return null;
133         }
134 
135         /// <summary>
136         /// 獲取屬性表示式
137         /// </summary>
138         /// <param name="expression"></param>
139         /// <param name="propertyName"></param>
140         public static MemberExpression GetPropertyExp(Expression expression, string propertyName)
141         {
142             string orginalName;
143 
144             switch (propertyName)
145             {
146                 case "標識":
147                     orginalName = "Guid";
148 
149                     break;
150 
151                 case "顏色":
152                     orginalName = "Color";
153                     break;
154 
155                 case "型別":
156                     orginalName = "Type";
157                     break;
158 
159                 case "圖層":
160                     orginalName = "Layer";
161                     break;
162 
163                 case "名稱":
164                     orginalName = "Name";
165                     break;
166 
167                 default:
168                     orginalName = propertyName;
169                     break;
170             }
171 
172             return Expression.Property(expression, orginalName);
173         }
174 
175         /// <summary>
176         /// 合併條件表示式
177         /// </summary>
178         /// <param name="left"></param>
179         /// <param name="right"></param>
180         /// <returns></returns>
181         public static BinaryExpression JionCondition(Expression left, Expression right)
182         {
183             return Expression.AndAlso(left, right);
184         }
185 
186         /// <summary>
187         /// 此處可省略
188         /// </summary>
189         /// <param name="propertyName"></param>
190         /// <param name="condition"></param>
191         /// <param name="content"></param>
192         /// <returns></returns>
193         [Obsolete("", true)]
194         private Func<UserDataProxy, bool> CreateLambda(string propertyName, EFilterOperator condition, string content)
195         {
196             string orginalName;
197 
198             switch (propertyName)
199             {
200                 case "標識":
201                     orginalName = "Guid";
202 
203                     break;
204 
205                 case "顏色":
206                     orginalName = "Color";
207                     break;
208 
209                 case "型別":
210                     orginalName = "Type";
211                     break;
212 
213                 case "圖層":
214                     orginalName = "Layer";
215                     break;
216 
217                 case "名稱":
218                     orginalName = "Name";
219                     break;
220 
221                 default:
222                     orginalName = propertyName;
223                     break;
224             }
225 
226             var paraExp = Expression.Parameter(typeof(UserDataProxy), "u");//原始型別
227 
228             var propertyExp = Expression.Property(paraExp, orginalName);//屬性定義
229 
230             if (content == null)
231             {
232                 return null;
233             }
234             var flag = double.TryParse(content, out double num);//轉換數字 能夠轉換是數字,不能就是文字
235 
236             Expression<Func<UserDataProxy, bool>> lambda = null;//最終結果
237             BinaryExpression exp;//二位運算子表示式
238 
239             Expression left;//左側表示式
240             ConstantExpression right;//右側表示式
241 
242             if (flag)
243             {
244                 left = Expression.Call(null, typeof(double).GetMethod("Parse", new Type[] { typeof(string) }), new Expression[] { propertyExp });
245 
246                 right = Expression.Constant(num, typeof(double));
247             }
248             else
249             {
250                 left = Expression.Call(propertyExp, typeof(string).GetMethod("ToString", new Type[] { }), new Expression[] { });//屬性轉換為字串
251                 right = Expression.Constant(content, typeof(string));
252             }
253 
254             MethodCallExpression callExp;
255             switch (condition)
256             {
257                 case EFilterOperator.Equal:
258                     if (!flag)
259                     {
260                         return null;
261                     }
262                     exp = Expression.Equal(left, right);
263                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
264                     break;
265 
266                 case EFilterOperator.NotEqual:
267                     if (!flag)
268                     {
269                         return null;
270                     }
271                     exp = Expression.NotEqual(left, right);
272                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
273                     break;
274 
275                 case EFilterOperator.GreaterThan:
276                     if (!flag)
277                     {
278                         return null;
279                     }
280                     exp = Expression.GreaterThan(left, right);
281                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
282                     break;
283 
284                 case EFilterOperator.LessThan:
285                     if (!flag)
286                     {
287                         return null;
288                     }
289                     exp = Expression.LessThan(left, right);
290                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
291                     break;
292 
293                 case EFilterOperator.GreaterThanOrEqual:
294                     if (!flag)
295                     {
296                         return null;
297                     }
298                     exp = Expression.GreaterThanOrEqual(left, right);
299                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
300                     break;
301 
302                 case EFilterOperator.LessThanOrEqual:
303                     if (!flag)
304                     {
305                         return null;
306                     }
307                     exp = Expression.LessThanOrEqual(left, right);
308                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(exp, new ParameterExpression[] { paraExp });
309                     break;
310 
311                 case EFilterOperator.StartsWith:
312                     callExp = Expression.Call(left, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), new Expression[] { right });
313                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
314                     break;
315 
316                 case EFilterOperator.EndWith:
317                     callExp = Expression.Call(left, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), new Expression[] { right });
318                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
319                     break;
320 
321                 case EFilterOperator.Contains:
322 
323                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
324                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(callExp, new ParameterExpression[] { paraExp });
325                     break;
326 
327                 case EFilterOperator.NotContains:
328                     callExp = Expression.Call(left, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), new Expression[] { right });
329                     lambda = Expression.Lambda<Func<UserDataProxy, bool>>(Expression.Not(callExp), new ParameterExpression[] { paraExp });
330                     break;
331             };
332 
333             return lambda.Compile();
334         }
335     }

執行測試

 1 internal class Program
 2     {
 3         public static Func<object, bool> Show()
 4         {
 5             return null;
 6         }
 7 
 8         private static void Main(string[] args)
 9         {
10             var list = new List<object>()
11             {
12                   new UserDataProxy(){Color="紅色",Name="王義夫",Length="120"},
13                   new UserDataProxy(){Color="綠色",Name="王受人",Length="2120"},
14                   new UserDataProxy(){Color="藍色",Name="王馬子",Length="920"},
15                   new UserDataProxy(){Color="白色",Name="張三義",Length="1120"},
16                   new UserDataProxy(){Color="紫色",Name="裡義夫",Length="1120"},
17                   new UserDataProxy(){Color="紅色",Name="王義夫",Length="1020"},
18                   new UserDataProxy(){Color="紅色",Name="王首任",Length="750"},
19                   new UserDataProxy(){Color="紅色",Name="李義夫",Length="1210"},
20                   new UserDataProxy(){Color="紅色",Name="勇義夫",Length="1110"},
21             };
22 
23             Console.WriteLine($"過濾之前\n");
24             list.ForEach(user =>
25             {
26                 var uu = user as UserDataProxy;
27 
28                 Console.WriteLine($"Color:{uu.Color},Length:{uu.Length},Name:{uu.Name}");
29             });
30 
31             var collection = CollectionViewSource.GetDefaultView(list);
32 
33             //第一個條件
34             var p1 = "Color";
35             var c1 = EFilterOperator.Contains;
36             var t1 = "";
37 
38             //第二個條件
39             var p2 = "Length";
40             var c2 = EFilterOperator.GreaterThan;
41             var t2 = "1000";
42 
43             //第三個條件
44             var p3 = "Name";
45             var c3 = EFilterOperator.NotContains;
46             var t3 = "";
47 
48             //生成條件1
49             var o = Expression.Parameter(typeof(object));
50 
51             var objExp = ExpressionTreeHelper.ConvertTo<UserDataProxy>(o);
52 
53             var m1 = ExpressionTreeHelper.GetPropertyExp(objExp, p1);
54 
55             var condition1 = ExpressionTreeHelper.CreateCondition(m1, c1, t1);
56 
57             //生成條件2
58             var m2 = ExpressionTreeHelper.GetPropertyExp(objExp, p2);
59 
60             var condition2 = ExpressionTreeHelper.CreateCondition(m2, c2, t2);
61 
62             //生成條件3
63             var m3 = ExpressionTreeHelper.GetPropertyExp(objExp, p3);
64 
65             var condition3 = ExpressionTreeHelper.CreateCondition(m3, c3, t3);
66 
67             //合併條件
68             var r1 = ExpressionTreeHelper.JionCondition(condition1, condition2);//第一次過濾
69 
70             //r1 = ExpressionTreeHelper.JionCondition(r1, condition3);//新增條件後過濾
71 
72             var s = Expression.Lambda<Predicate<object>>(r1, o);//建立Lambda表示式
73 
74             var func = s.Compile();//編譯成委託
75 
76             if (func != null)
77             {
78                 //屬性可能為null,在此處丟擲異常
79                 try
80                 {
81                     collection.Filter = func;
82                     collection.Refresh();
83                 }
84                 catch (Exception ex)
85                 {
86                     Console.WriteLine($"{ex.Message}");
87                 }
88             }
89 
90             Console.WriteLine($"過濾之後\n");
91             foreach (var item in collection)
92             {
93                 var u = item as UserDataProxy;
94 
95                 Console.WriteLine($"Color:{u.Color},Length:{u.Length},Name:{u.Name}");
96             }
97         }
98     }

第一次過濾結果

第二次過濾結果