0
|
1 using System;
|
|
2 using System.Collections.Generic;
|
|
3 using System.Linq;
|
|
4 using System.Linq.Expressions;
|
|
5 using System.Reflection;
|
|
6
|
|
7 using BLToolkit.Data.Linq.Builder;
|
|
8
|
|
9 // ReSharper disable ConditionIsAlwaysTrueOrFalse
|
|
10 // ReSharper disable HeuristicUnreachableCode
|
|
11
|
|
12 namespace BLToolkit.Linq
|
|
13 {
|
|
14 using Data.Linq;
|
|
15 using Reflection;
|
|
16
|
|
17 public static class ExpressionHelper
|
|
18 {
|
|
19 #region IsConstant
|
|
20
|
|
21 public static bool IsConstant(Type type)
|
|
22 {
|
|
23 if (type.IsEnum)
|
|
24 return true;
|
|
25
|
|
26 switch (Type.GetTypeCode(type))
|
|
27 {
|
|
28 case TypeCode.Int16 :
|
|
29 case TypeCode.Int32 :
|
|
30 case TypeCode.Int64 :
|
|
31 case TypeCode.UInt16 :
|
|
32 case TypeCode.UInt32 :
|
|
33 case TypeCode.UInt64 :
|
|
34 case TypeCode.SByte :
|
|
35 case TypeCode.Byte :
|
|
36 case TypeCode.Decimal :
|
|
37 case TypeCode.Double :
|
|
38 case TypeCode.Single :
|
|
39 case TypeCode.Boolean :
|
|
40 case TypeCode.String :
|
|
41 case TypeCode.Char : return true;
|
|
42 }
|
|
43
|
|
44 if (TypeHelper.IsNullableType(type))
|
|
45 return IsConstant(type.GetGenericArguments()[0]);
|
|
46
|
|
47 return false;
|
|
48 }
|
|
49
|
|
50 #endregion
|
|
51
|
|
52 #region Compare
|
|
53
|
|
54 internal static bool Compare(Expression expr1, Expression expr2, Dictionary<Expression,QueryableAccessor> queryableAccessorDic)
|
|
55 {
|
|
56 return Compare(expr1, expr2, new HashSet<Expression>(), queryableAccessorDic);
|
|
57 }
|
|
58
|
|
59 static bool Compare(
|
|
60 Expression expr1,
|
|
61 Expression expr2,
|
|
62 HashSet<Expression> visited,
|
|
63 Dictionary<Expression,QueryableAccessor> queryableAccessorDic)
|
|
64 {
|
|
65 if (expr1 == expr2)
|
|
66 return true;
|
|
67
|
|
68 if (expr1 == null || expr2 == null || expr1.NodeType != expr2.NodeType || expr1.Type != expr2.Type)
|
|
69 return false;
|
|
70
|
|
71 switch (expr1.NodeType)
|
|
72 {
|
|
73 case ExpressionType.Add:
|
|
74 case ExpressionType.AddChecked:
|
|
75 case ExpressionType.And:
|
|
76 case ExpressionType.AndAlso:
|
|
77 case ExpressionType.ArrayIndex:
|
|
78 #if FW4 || SILVERLIGHT
|
|
79 case ExpressionType.Assign:
|
|
80 #endif
|
|
81 case ExpressionType.Coalesce:
|
|
82 case ExpressionType.Divide:
|
|
83 case ExpressionType.Equal:
|
|
84 case ExpressionType.ExclusiveOr:
|
|
85 case ExpressionType.GreaterThan:
|
|
86 case ExpressionType.GreaterThanOrEqual:
|
|
87 case ExpressionType.LeftShift:
|
|
88 case ExpressionType.LessThan:
|
|
89 case ExpressionType.LessThanOrEqual:
|
|
90 case ExpressionType.Modulo:
|
|
91 case ExpressionType.Multiply:
|
|
92 case ExpressionType.MultiplyChecked:
|
|
93 case ExpressionType.NotEqual:
|
|
94 case ExpressionType.Or:
|
|
95 case ExpressionType.OrElse:
|
|
96 case ExpressionType.Power:
|
|
97 case ExpressionType.RightShift:
|
|
98 case ExpressionType.Subtract:
|
|
99 case ExpressionType.SubtractChecked:
|
|
100 {
|
|
101 var e1 = (BinaryExpression)expr1;
|
|
102 var e2 = (BinaryExpression)expr2;
|
|
103 return
|
|
104 e1.Method == e2.Method &&
|
|
105 Compare(e1.Conversion, e2.Conversion, visited, queryableAccessorDic) &&
|
|
106 Compare(e1.Left, e2.Left, visited, queryableAccessorDic) &&
|
|
107 Compare(e1.Right, e2.Right, visited, queryableAccessorDic);
|
|
108 }
|
|
109
|
|
110 case ExpressionType.ArrayLength:
|
|
111 case ExpressionType.Convert:
|
|
112 case ExpressionType.ConvertChecked:
|
|
113 case ExpressionType.Negate:
|
|
114 case ExpressionType.NegateChecked:
|
|
115 case ExpressionType.Not:
|
|
116 case ExpressionType.Quote:
|
|
117 case ExpressionType.TypeAs:
|
|
118 case ExpressionType.UnaryPlus:
|
|
119 {
|
|
120 var e1 = (UnaryExpression)expr1;
|
|
121 var e2 = (UnaryExpression)expr2;
|
|
122 return e1.Method == e2.Method && Compare(e1.Operand, e2.Operand, visited, queryableAccessorDic);
|
|
123 }
|
|
124
|
|
125 case ExpressionType.Call:
|
|
126 {
|
|
127 var e1 = (MethodCallExpression)expr1;
|
|
128 var e2 = (MethodCallExpression)expr2;
|
|
129
|
|
130 if (e1.Arguments.Count != e2.Arguments.Count || e1.Method != e2.Method)
|
|
131 return false;
|
|
132
|
|
133 if (queryableAccessorDic.Count > 0)
|
|
134 {
|
|
135 QueryableAccessor qa;
|
|
136
|
|
137 if (queryableAccessorDic.TryGetValue(expr1, out qa))
|
|
138 return Compare(qa.Queryable.Expression, qa.Accessor(expr2).Expression, visited, queryableAccessorDic);
|
|
139 }
|
|
140
|
|
141 if (!Compare(e1.Object, e2.Object, visited, queryableAccessorDic))
|
|
142 return false;
|
|
143
|
|
144 for (var i = 0; i < e1.Arguments.Count; i++)
|
|
145 if (!Compare(e1.Arguments[i], e2.Arguments[i], visited, queryableAccessorDic))
|
|
146 return false;
|
|
147
|
|
148 return true;
|
|
149 }
|
|
150
|
|
151 case ExpressionType.Conditional:
|
|
152 {
|
|
153 var e1 = (ConditionalExpression)expr1;
|
|
154 var e2 = (ConditionalExpression)expr2;
|
|
155 return
|
|
156 Compare(e1.Test, e2.Test, visited, queryableAccessorDic) &&
|
|
157 Compare(e1.IfTrue, e2.IfTrue, visited, queryableAccessorDic) &&
|
|
158 Compare(e1.IfFalse, e2.IfFalse, visited, queryableAccessorDic);
|
|
159 }
|
|
160
|
|
161 case ExpressionType.Constant:
|
|
162 {
|
|
163 var e1 = (ConstantExpression)expr1;
|
|
164 var e2 = (ConstantExpression)expr2;
|
|
165
|
|
166 if (e1.Value == null && e2.Value == null)
|
|
167 return true;
|
|
168
|
|
169 if (IsConstant(e1.Type))
|
|
170 return Equals(e1.Value, e2.Value);
|
|
171
|
|
172 if (e1.Value == null || e2.Value == null)
|
|
173 return false;
|
|
174
|
|
175 if (e1.Value is IQueryable)
|
|
176 {
|
|
177 var eq1 = ((IQueryable)e1.Value).Expression;
|
|
178 var eq2 = ((IQueryable)e2.Value).Expression;
|
|
179
|
|
180 if (visited.Add(eq1))
|
|
181 return Compare(eq1, eq2, visited, queryableAccessorDic);
|
|
182 }
|
|
183
|
|
184 return true;
|
|
185 }
|
|
186
|
|
187 case ExpressionType.Invoke:
|
|
188 {
|
|
189 var e1 = (InvocationExpression)expr1;
|
|
190 var e2 = (InvocationExpression)expr2;
|
|
191
|
|
192 if (e1.Arguments.Count != e2.Arguments.Count || !Compare(e1.Expression, e2.Expression, visited, queryableAccessorDic))
|
|
193 return false;
|
|
194
|
|
195 for (var i = 0; i < e1.Arguments.Count; i++)
|
|
196 if (!Compare(e1.Arguments[i], e2.Arguments[i], visited, queryableAccessorDic))
|
|
197 return false;
|
|
198
|
|
199 return true;
|
|
200 }
|
|
201
|
|
202 case ExpressionType.Lambda:
|
|
203 {
|
|
204 var e1 = (LambdaExpression)expr1;
|
|
205 var e2 = (LambdaExpression)expr2;
|
|
206
|
|
207 if (e1.Parameters.Count != e2.Parameters.Count || !Compare(e1.Body, e2.Body, visited, queryableAccessorDic))
|
|
208 return false;
|
|
209
|
|
210 for (var i = 0; i < e1.Parameters.Count; i++)
|
|
211 if (!Compare(e1.Parameters[i], e2.Parameters[i], visited, queryableAccessorDic))
|
|
212 return false;
|
|
213
|
|
214 return true;
|
|
215 }
|
|
216
|
|
217 case ExpressionType.ListInit:
|
|
218 {
|
|
219 var e1 = (ListInitExpression)expr1;
|
|
220 var e2 = (ListInitExpression)expr2;
|
|
221
|
|
222 if (e1.Initializers.Count != e2.Initializers.Count || !Compare(e1.NewExpression, e2.NewExpression, visited, queryableAccessorDic))
|
|
223 return false;
|
|
224
|
|
225 for (var i = 0; i < e1.Initializers.Count; i++)
|
|
226 {
|
|
227 var i1 = e1.Initializers[i];
|
|
228 var i2 = e2.Initializers[i];
|
|
229
|
|
230 if (i1.Arguments.Count != i2.Arguments.Count || i1.AddMethod != i2.AddMethod)
|
|
231 return false;
|
|
232
|
|
233 for (var j = 0; j < i1.Arguments.Count; j++)
|
|
234 if (!Compare(i1.Arguments[j], i2.Arguments[j], visited, queryableAccessorDic))
|
|
235 return false;
|
|
236 }
|
|
237
|
|
238 return true;
|
|
239 }
|
|
240
|
|
241 case ExpressionType.MemberAccess:
|
|
242 {
|
|
243 var e1 = (MemberExpression)expr1;
|
|
244 var e2 = (MemberExpression)expr2;
|
|
245
|
|
246 if (e1.Member == e2.Member)
|
|
247 {
|
|
248 if (e1.Expression == e2.Expression || e1.Expression.Type == e2.Expression.Type)
|
|
249 {
|
|
250 if (queryableAccessorDic.Count > 0)
|
|
251 {
|
|
252 QueryableAccessor qa;
|
|
253
|
|
254 if (queryableAccessorDic.TryGetValue(expr1, out qa))
|
|
255 return
|
|
256 Compare(e1.Expression, e2.Expression, visited, queryableAccessorDic) &&
|
|
257 Compare(qa.Queryable.Expression, qa.Accessor(expr2).Expression, visited, queryableAccessorDic);
|
|
258 }
|
|
259 }
|
|
260
|
|
261 return Compare(e1.Expression, e2.Expression, visited, queryableAccessorDic);
|
|
262 }
|
|
263
|
|
264 return false;
|
|
265 }
|
|
266
|
|
267 case ExpressionType.MemberInit:
|
|
268 {
|
|
269 var e1 = (MemberInitExpression)expr1;
|
|
270 var e2 = (MemberInitExpression)expr2;
|
|
271
|
|
272 if (e1.Bindings.Count != e2.Bindings.Count || !Compare(e1.NewExpression, e2.NewExpression, visited, queryableAccessorDic))
|
|
273 return false;
|
|
274
|
|
275 Func<MemberBinding,MemberBinding,bool> compareBindings = null; compareBindings = (b1,b2) =>
|
|
276 {
|
|
277 if (b1 == b2)
|
|
278 return true;
|
|
279
|
|
280 if (b1 == null || b2 == null || b1.BindingType != b2.BindingType || b1.Member != b2.Member)
|
|
281 return false;
|
|
282
|
|
283 switch (b1.BindingType)
|
|
284 {
|
|
285 case MemberBindingType.Assignment:
|
|
286 return Compare(((MemberAssignment)b1).Expression, ((MemberAssignment)b2).Expression, visited, queryableAccessorDic);
|
|
287
|
|
288 case MemberBindingType.ListBinding:
|
|
289 var ml1 = (MemberListBinding)b1;
|
|
290 var ml2 = (MemberListBinding)b2;
|
|
291
|
|
292 if (ml1.Initializers.Count != ml2.Initializers.Count)
|
|
293 return false;
|
|
294
|
|
295 for (var i = 0; i < ml1.Initializers.Count; i++)
|
|
296 {
|
|
297 var ei1 = ml1.Initializers[i];
|
|
298 var ei2 = ml2.Initializers[i];
|
|
299
|
|
300 if (ei1.AddMethod != ei2.AddMethod || ei1.Arguments.Count != ei2.Arguments.Count)
|
|
301 return false;
|
|
302
|
|
303 for (var j = 0; j < ei1.Arguments.Count; j++)
|
|
304 if (!Compare(ei1.Arguments[j], ei2.Arguments[j], visited, queryableAccessorDic))
|
|
305 return false;
|
|
306 }
|
|
307
|
|
308 break;
|
|
309
|
|
310 case MemberBindingType.MemberBinding:
|
|
311 var mm1 = (MemberMemberBinding)b1;
|
|
312 var mm2 = (MemberMemberBinding)b2;
|
|
313
|
|
314 if (mm1.Bindings.Count != mm2.Bindings.Count)
|
|
315 return false;
|
|
316
|
|
317 for (var i = 0; i < mm1.Bindings.Count; i++)
|
|
318 if (!compareBindings(mm1.Bindings[i], mm2.Bindings[i]))
|
|
319 return false;
|
|
320
|
|
321 break;
|
|
322 }
|
|
323
|
|
324 return true;
|
|
325 };
|
|
326
|
|
327 for (var i = 0; i < e1.Bindings.Count; i++)
|
|
328 {
|
|
329 var b1 = e1.Bindings[i];
|
|
330 var b2 = e2.Bindings[i];
|
|
331
|
|
332 if (!compareBindings(b1, b2))
|
|
333 return false;
|
|
334 }
|
|
335
|
|
336 return true;
|
|
337 }
|
|
338
|
|
339 case ExpressionType.New:
|
|
340 {
|
|
341 var e1 = (NewExpression)expr1;
|
|
342 var e2 = (NewExpression)expr2;
|
|
343
|
|
344 if (e1.Arguments.Count != e2.Arguments.Count)
|
|
345 return false;
|
|
346
|
|
347 if (e1.Members == null && e2.Members != null)
|
|
348 return false;
|
|
349
|
|
350 if (e1.Members != null && e2.Members == null)
|
|
351 return false;
|
|
352
|
|
353 if (e1.Constructor != e2.Constructor)
|
|
354 return false;
|
|
355
|
|
356 if (e1.Members != null)
|
|
357 {
|
|
358 if (e1.Members.Count != e2.Members.Count)
|
|
359 return false;
|
|
360
|
|
361 for (var i = 0; i < e1.Members.Count; i++)
|
|
362 if (e1.Members[i] != e2.Members[i])
|
|
363 return false;
|
|
364 }
|
|
365
|
|
366 for (var i = 0; i < e1.Arguments.Count; i++)
|
|
367 if (!Compare(e1.Arguments[i], e2.Arguments[i], visited, queryableAccessorDic))
|
|
368 return false;
|
|
369
|
|
370 return true;
|
|
371 }
|
|
372
|
|
373 case ExpressionType.NewArrayBounds:
|
|
374 case ExpressionType.NewArrayInit:
|
|
375 {
|
|
376 var e1 = (NewArrayExpression)expr1;
|
|
377 var e2 = (NewArrayExpression)expr2;
|
|
378
|
|
379 if (e1.Expressions.Count != e2.Expressions.Count)
|
|
380 return false;
|
|
381
|
|
382 for (var i = 0; i < e1.Expressions.Count; i++)
|
|
383 if (!Compare(e1.Expressions[i], e2.Expressions[i], visited, queryableAccessorDic))
|
|
384 return false;
|
|
385
|
|
386 return true;
|
|
387 }
|
|
388
|
|
389 case ExpressionType.Parameter:
|
|
390 {
|
|
391 var e1 = (ParameterExpression)expr1;
|
|
392 var e2 = (ParameterExpression)expr2;
|
|
393 return e1.Name == e2.Name;
|
|
394 }
|
|
395
|
|
396 case ExpressionType.TypeIs:
|
|
397 {
|
|
398 var e1 = (TypeBinaryExpression)expr1;
|
|
399 var e2 = (TypeBinaryExpression)expr2;
|
|
400 return e1.TypeOperand == e2.TypeOperand && Compare(e1.Expression, e2.Expression, visited, queryableAccessorDic);
|
|
401 }
|
|
402
|
|
403 #if FW4 || SILVERLIGHT
|
|
404
|
|
405 case ExpressionType.Block:
|
|
406 {
|
|
407 var e1 = (BlockExpression)expr1;
|
|
408 var e2 = (BlockExpression)expr2;
|
|
409
|
|
410 for (var i = 0; i < e1.Expressions.Count; i++)
|
|
411 if (!Compare(e1.Expressions[i], e2.Expressions[i], visited, queryableAccessorDic))
|
|
412 return false;
|
|
413
|
|
414 for (var i = 0; i < e1.Variables.Count; i++)
|
|
415 if (!Compare(e1.Variables[i], e2.Variables[i], visited, queryableAccessorDic))
|
|
416 return false;
|
|
417
|
|
418 return true;
|
|
419 }
|
|
420
|
|
421 #endif
|
|
422 }
|
|
423
|
|
424 throw new InvalidOperationException();
|
|
425 }
|
|
426
|
|
427 #endregion
|
|
428
|
|
429 #region Path
|
|
430
|
|
431 static Expression ConvertTo(Expression expr, Type type)
|
|
432 {
|
|
433 return Expression.Convert(expr, type);
|
|
434 }
|
|
435
|
|
436 static void Path<T>(IEnumerable<T> source, HashSet<Expression> visited, Expression path, MethodInfo property, Action<T,Expression> func)
|
|
437 where T : class
|
|
438 {
|
|
439 var prop = Expression.Property(path, property);
|
|
440 var i = 0;
|
|
441 foreach (var item in source)
|
|
442 func(item, Expression.Call(prop, ReflectionHelper.IndexExpressor<T>.Item, new Expression[] { Expression.Constant(i++) }));
|
|
443 }
|
|
444
|
|
445 static void Path<T>(IEnumerable<T> source, HashSet<Expression> visited, Expression path, MethodInfo property, Action<Expression,Expression> func)
|
|
446 where T : Expression
|
|
447 {
|
|
448 var prop = Expression.Property(path, property);
|
|
449 var i = 0;
|
|
450 foreach (var item in source)
|
|
451 Path(item, visited, Expression.Call(prop, ReflectionHelper.IndexExpressor<T>.Item, new Expression[] { Expression.Constant(i++) }), func);
|
|
452 }
|
|
453
|
|
454 static void Path(Expression expr, HashSet<Expression> visited, Expression path, MethodInfo property, Action<Expression,Expression> func)
|
|
455 {
|
|
456 Path(expr, visited, Expression.Property(path, property), func);
|
|
457 }
|
|
458
|
|
459 public static void Path(this Expression expr, Expression path, Action<Expression,Expression> func)
|
|
460 {
|
|
461 Path(expr, new HashSet<Expression>(), path, func);
|
|
462 }
|
|
463
|
|
464 static void Path(
|
|
465 this Expression expr,
|
|
466 HashSet<Expression> visited,
|
|
467 Expression path,
|
|
468 Action<Expression,Expression> func)
|
|
469 {
|
|
470 if (expr == null)
|
|
471 return;
|
|
472
|
|
473 switch (expr.NodeType)
|
|
474 {
|
|
475 case ExpressionType.Add:
|
|
476 case ExpressionType.AddChecked:
|
|
477 case ExpressionType.And:
|
|
478 case ExpressionType.AndAlso:
|
|
479 case ExpressionType.ArrayIndex:
|
|
480 #if FW4 || SILVERLIGHT
|
|
481 case ExpressionType.Assign:
|
|
482 #endif
|
|
483 case ExpressionType.Coalesce:
|
|
484 case ExpressionType.Divide:
|
|
485 case ExpressionType.Equal:
|
|
486 case ExpressionType.ExclusiveOr:
|
|
487 case ExpressionType.GreaterThan:
|
|
488 case ExpressionType.GreaterThanOrEqual:
|
|
489 case ExpressionType.LeftShift:
|
|
490 case ExpressionType.LessThan:
|
|
491 case ExpressionType.LessThanOrEqual:
|
|
492 case ExpressionType.Modulo:
|
|
493 case ExpressionType.Multiply:
|
|
494 case ExpressionType.MultiplyChecked:
|
|
495 case ExpressionType.NotEqual:
|
|
496 case ExpressionType.Or:
|
|
497 case ExpressionType.OrElse:
|
|
498 case ExpressionType.Power:
|
|
499 case ExpressionType.RightShift:
|
|
500 case ExpressionType.Subtract:
|
|
501 case ExpressionType.SubtractChecked:
|
|
502 {
|
|
503 path = ConvertTo(path, typeof(BinaryExpression));
|
|
504 var e = (BinaryExpression)expr;
|
|
505
|
|
506 Path(e.Conversion, visited, path, ReflectionHelper.Binary.Conversion, func);
|
|
507 Path(e.Left, visited, path, ReflectionHelper.Binary.Left, func);
|
|
508 Path(e.Right, visited, path, ReflectionHelper.Binary.Right, func);
|
|
509
|
|
510 break;
|
|
511 }
|
|
512
|
|
513 case ExpressionType.ArrayLength:
|
|
514 case ExpressionType.Convert:
|
|
515 case ExpressionType.ConvertChecked:
|
|
516 case ExpressionType.Negate:
|
|
517 case ExpressionType.NegateChecked:
|
|
518 case ExpressionType.Not:
|
|
519 case ExpressionType.Quote:
|
|
520 case ExpressionType.TypeAs:
|
|
521 case ExpressionType.UnaryPlus:
|
|
522 Path(
|
|
523 ((UnaryExpression)expr).Operand,
|
|
524 visited,
|
|
525 path = ConvertTo(path, typeof(UnaryExpression)),
|
|
526 ReflectionHelper.Unary.Operand,
|
|
527 func);
|
|
528 break;
|
|
529
|
|
530 case ExpressionType.Call:
|
|
531 {
|
|
532 path = ConvertTo(path, typeof(MethodCallExpression));
|
|
533 var e = (MethodCallExpression)expr;
|
|
534
|
|
535 Path(e.Object, visited, path, ReflectionHelper.MethodCall.Object, func);
|
|
536 Path(e.Arguments, visited, path, ReflectionHelper.MethodCall.Arguments, func);
|
|
537
|
|
538 break;
|
|
539 }
|
|
540
|
|
541 case ExpressionType.Conditional:
|
|
542 {
|
|
543 path = ConvertTo(path, typeof(ConditionalExpression));
|
|
544 var e = (ConditionalExpression)expr;
|
|
545
|
|
546 Path(e.Test, visited, path, ReflectionHelper.Conditional.Test, func);
|
|
547 Path(e.IfTrue, visited, path, ReflectionHelper.Conditional.IfTrue, func);
|
|
548 Path(e.IfFalse, visited, path, ReflectionHelper.Conditional.IfFalse, func);
|
|
549
|
|
550 break;
|
|
551 }
|
|
552
|
|
553 case ExpressionType.Invoke:
|
|
554 {
|
|
555 path = ConvertTo(path, typeof(InvocationExpression));
|
|
556 var e = (InvocationExpression)expr;
|
|
557
|
|
558 Path(e.Expression, visited, path, ReflectionHelper.Invocation.Expression, func);
|
|
559 Path(e.Arguments, visited, path, ReflectionHelper.Invocation.Arguments, func);
|
|
560
|
|
561 break;
|
|
562 }
|
|
563
|
|
564 case ExpressionType.Lambda:
|
|
565 {
|
|
566 path = ConvertTo(path, typeof(LambdaExpression));
|
|
567 var e = (LambdaExpression)expr;
|
|
568
|
|
569 Path(e.Body, visited, path, ReflectionHelper.LambdaExpr.Body, func);
|
|
570 Path(e.Parameters, visited, path, ReflectionHelper.LambdaExpr.Parameters, func);
|
|
571
|
|
572 break;
|
|
573 }
|
|
574
|
|
575 case ExpressionType.ListInit:
|
|
576 {
|
|
577 path = ConvertTo(path, typeof(ListInitExpression));
|
|
578 var e = (ListInitExpression)expr;
|
|
579
|
|
580 Path(e.NewExpression, visited, path, ReflectionHelper.ListInit.NewExpression, func);
|
|
581 Path(e.Initializers, visited, path, ReflectionHelper.ListInit.Initializers,
|
|
582 (ex,p) => Path(ex.Arguments, visited, p, ReflectionHelper.ElementInit.Arguments, func));
|
|
583
|
|
584 break;
|
|
585 }
|
|
586
|
|
587 case ExpressionType.MemberAccess:
|
|
588 Path(
|
|
589 ((MemberExpression)expr).Expression,
|
|
590 visited,
|
|
591 path = ConvertTo(path, typeof(MemberExpression)),
|
|
592 ReflectionHelper.Member.Expression,
|
|
593 func);
|
|
594 break;
|
|
595
|
|
596 case ExpressionType.MemberInit:
|
|
597 {
|
|
598 Action<MemberBinding,Expression> modify = null; modify = (b,pinf) =>
|
|
599 {
|
|
600 switch (b.BindingType)
|
|
601 {
|
|
602 case MemberBindingType.Assignment:
|
|
603 Path(
|
|
604 ((MemberAssignment)b).Expression,
|
|
605 visited,
|
|
606 ConvertTo(pinf, typeof(MemberAssignment)),
|
|
607 ReflectionHelper.MemberAssignmentBind.Expression,
|
|
608 func);
|
|
609 break;
|
|
610
|
|
611 case MemberBindingType.ListBinding:
|
|
612 Path(
|
|
613 ((MemberListBinding)b).Initializers,
|
|
614 visited,
|
|
615 ConvertTo(pinf, typeof(MemberListBinding)),
|
|
616 ReflectionHelper.MemberListBind.Initializers,
|
|
617 (p,psi) => Path(p.Arguments, visited, psi, ReflectionHelper.ElementInit.Arguments, func));
|
|
618 break;
|
|
619
|
|
620 case MemberBindingType.MemberBinding:
|
|
621 Path(
|
|
622 ((MemberMemberBinding)b).Bindings,
|
|
623 visited,
|
|
624 ConvertTo(pinf, typeof(MemberMemberBinding)),
|
|
625 ReflectionHelper.MemberMemberBind.Bindings,
|
|
626 modify);
|
|
627 break;
|
|
628 }
|
|
629 };
|
|
630
|
|
631 path = ConvertTo(path, typeof(MemberInitExpression));
|
|
632 var e = (MemberInitExpression)expr;
|
|
633
|
|
634 Path(e.NewExpression, visited, path, ReflectionHelper.MemberInit.NewExpression, func);
|
|
635 Path(e.Bindings, visited, path, ReflectionHelper.MemberInit.Bindings, modify);
|
|
636
|
|
637 break;
|
|
638 }
|
|
639
|
|
640 case ExpressionType.New:
|
|
641 Path(
|
|
642 ((NewExpression)expr).Arguments,
|
|
643 visited,
|
|
644 path = ConvertTo(path, typeof(NewExpression)),
|
|
645 ReflectionHelper.New.Arguments,
|
|
646 func);
|
|
647 break;
|
|
648
|
|
649 case ExpressionType.NewArrayBounds:
|
|
650 Path(
|
|
651 ((NewArrayExpression)expr).Expressions,
|
|
652 visited,
|
|
653 path = ConvertTo(path, typeof(NewArrayExpression)),
|
|
654 ReflectionHelper.NewArray.Expressions,
|
|
655 func);
|
|
656 break;
|
|
657
|
|
658 case ExpressionType.NewArrayInit:
|
|
659 Path(
|
|
660 ((NewArrayExpression)expr).Expressions,
|
|
661 visited,
|
|
662 path = ConvertTo(path, typeof(NewArrayExpression)),
|
|
663 ReflectionHelper.NewArray.Expressions,
|
|
664 func);
|
|
665 break;
|
|
666
|
|
667 case ExpressionType.TypeIs:
|
|
668 Path(
|
|
669 ((TypeBinaryExpression)expr).Expression,
|
|
670 visited,
|
|
671 path = ConvertTo(path, typeof(TypeBinaryExpression)),
|
|
672 ReflectionHelper.TypeBinary.Expression,
|
|
673 func);
|
|
674 break;
|
|
675
|
|
676 #if FW4 || SILVERLIGHT
|
|
677
|
|
678 case ExpressionType.Block:
|
|
679 {
|
|
680 path = ConvertTo(path, typeof(BlockExpression));
|
|
681 var e = (BlockExpression)expr;
|
|
682
|
|
683 Path(e.Expressions, visited, path, ReflectionHelper.Block.Expressions, func);
|
|
684 Path(e.Variables, visited, path, ReflectionHelper.Block.Variables, func); // ?
|
|
685
|
|
686 break;
|
|
687 }
|
|
688
|
|
689 #endif
|
|
690
|
|
691 case ExpressionType.Constant :
|
|
692 {
|
|
693 path = ConvertTo(path, typeof(ConstantExpression));
|
|
694 var e = (ConstantExpression)expr;
|
|
695 var iq = e.Value as IQueryable;
|
|
696
|
|
697 if (iq != null && !visited.Contains(iq.Expression))
|
|
698 {
|
|
699 visited.Add(iq.Expression);
|
|
700
|
|
701 Expression p = Expression.Property(path, ReflectionHelper.Constant.Value);
|
|
702 p = ConvertTo(p, typeof(IQueryable));
|
|
703 Path(iq.Expression, visited, p, ReflectionHelper.QueryableInt.Expression, func);
|
|
704 }
|
|
705
|
|
706 break;
|
|
707 }
|
|
708
|
|
709 case ExpressionType.Parameter: path = ConvertTo(path, typeof(ParameterExpression)); break;
|
|
710 }
|
|
711
|
|
712 func(expr, path);
|
|
713 }
|
|
714
|
|
715 #endregion
|
|
716
|
|
717 #region Visit
|
|
718
|
|
719 static void Visit<T>(IEnumerable<T> source, Action<T> func)
|
|
720 {
|
|
721 foreach (var item in source)
|
|
722 func(item);
|
|
723 }
|
|
724
|
|
725 static void Visit<T>(IEnumerable<T> source, Action<Expression> func)
|
|
726 where T : Expression
|
|
727 {
|
|
728 foreach (var item in source)
|
|
729 Visit(item, func);
|
|
730 }
|
|
731
|
|
732 public static void Visit(this Expression expr, Action<Expression> func)
|
|
733 {
|
|
734 if (expr == null)
|
|
735 return;
|
|
736
|
|
737 switch (expr.NodeType)
|
|
738 {
|
|
739 case ExpressionType.Add:
|
|
740 case ExpressionType.AddChecked:
|
|
741 case ExpressionType.And:
|
|
742 case ExpressionType.AndAlso:
|
|
743 case ExpressionType.ArrayIndex:
|
|
744 #if FW4 || SILVERLIGHT
|
|
745 case ExpressionType.Assign:
|
|
746 #endif
|
|
747 case ExpressionType.Coalesce:
|
|
748 case ExpressionType.Divide:
|
|
749 case ExpressionType.Equal:
|
|
750 case ExpressionType.ExclusiveOr:
|
|
751 case ExpressionType.GreaterThan:
|
|
752 case ExpressionType.GreaterThanOrEqual:
|
|
753 case ExpressionType.LeftShift:
|
|
754 case ExpressionType.LessThan:
|
|
755 case ExpressionType.LessThanOrEqual:
|
|
756 case ExpressionType.Modulo:
|
|
757 case ExpressionType.Multiply:
|
|
758 case ExpressionType.MultiplyChecked:
|
|
759 case ExpressionType.NotEqual:
|
|
760 case ExpressionType.Or:
|
|
761 case ExpressionType.OrElse:
|
|
762 case ExpressionType.Power:
|
|
763 case ExpressionType.RightShift:
|
|
764 case ExpressionType.Subtract:
|
|
765 case ExpressionType.SubtractChecked:
|
|
766 {
|
|
767 var e = (BinaryExpression)expr;
|
|
768
|
|
769 Visit(e.Conversion, func);
|
|
770 Visit(e.Left, func);
|
|
771 Visit(e.Right, func);
|
|
772
|
|
773 break;
|
|
774 }
|
|
775
|
|
776 case ExpressionType.ArrayLength:
|
|
777 case ExpressionType.Convert:
|
|
778 case ExpressionType.ConvertChecked:
|
|
779 case ExpressionType.Negate:
|
|
780 case ExpressionType.NegateChecked:
|
|
781 case ExpressionType.Not:
|
|
782 case ExpressionType.Quote:
|
|
783 case ExpressionType.TypeAs:
|
|
784 case ExpressionType.UnaryPlus:
|
|
785 Visit(((UnaryExpression)expr).Operand, func);
|
|
786 break;
|
|
787
|
|
788 case ExpressionType.Call:
|
|
789 {
|
|
790 var e = (MethodCallExpression)expr;
|
|
791
|
|
792 Visit(e.Object, func);
|
|
793 Visit(e.Arguments, func);
|
|
794
|
|
795 break;
|
|
796 }
|
|
797
|
|
798 case ExpressionType.Conditional:
|
|
799 {
|
|
800 var e = (ConditionalExpression)expr;
|
|
801
|
|
802 Visit(e.Test, func);
|
|
803 Visit(e.IfTrue, func);
|
|
804 Visit(e.IfFalse, func);
|
|
805
|
|
806 break;
|
|
807 }
|
|
808
|
|
809 case ExpressionType.Invoke:
|
|
810 {
|
|
811 var e = (InvocationExpression)expr;
|
|
812
|
|
813 Visit(e.Expression, func);
|
|
814 Visit(e.Arguments, func);
|
|
815
|
|
816 break;
|
|
817 }
|
|
818
|
|
819 case ExpressionType.Lambda:
|
|
820 {
|
|
821 var e = (LambdaExpression)expr;
|
|
822
|
|
823 Visit(e.Body, func);
|
|
824 Visit(e.Parameters, func);
|
|
825
|
|
826 break;
|
|
827 }
|
|
828
|
|
829 case ExpressionType.ListInit:
|
|
830 {
|
|
831 var e = (ListInitExpression)expr;
|
|
832
|
|
833 Visit(e.NewExpression, func);
|
|
834 Visit(e.Initializers, ex => Visit(ex.Arguments, func));
|
|
835
|
|
836 break;
|
|
837 }
|
|
838
|
|
839 case ExpressionType.MemberAccess: Visit(((MemberExpression)expr).Expression, func); break;
|
|
840
|
|
841 case ExpressionType.MemberInit:
|
|
842 {
|
|
843 Action<MemberBinding> modify = null; modify = b =>
|
|
844 {
|
|
845 switch (b.BindingType)
|
|
846 {
|
|
847 case MemberBindingType.Assignment : Visit(((MemberAssignment)b). Expression, func); break;
|
|
848 case MemberBindingType.ListBinding : Visit(((MemberListBinding)b).Initializers, p => Visit(p.Arguments, func)); break;
|
|
849 case MemberBindingType.MemberBinding : Visit(((MemberMemberBinding)b).Bindings, modify); break;
|
|
850 }
|
|
851 };
|
|
852
|
|
853 var e = (MemberInitExpression)expr;
|
|
854
|
|
855 Visit(e.NewExpression, func);
|
|
856 Visit(e.Bindings, modify);
|
|
857
|
|
858 break;
|
|
859 }
|
|
860
|
|
861 case ExpressionType.New : Visit(((NewExpression) expr).Arguments, func); break;
|
|
862 case ExpressionType.NewArrayBounds : Visit(((NewArrayExpression) expr).Expressions, func); break;
|
|
863 case ExpressionType.NewArrayInit : Visit(((NewArrayExpression) expr).Expressions, func); break;
|
|
864 case ExpressionType.TypeIs : Visit(((TypeBinaryExpression)expr).Expression, func); break;
|
|
865
|
|
866 #if FW4 || SILVERLIGHT
|
|
867
|
|
868 case ExpressionType.Block:
|
|
869 {
|
|
870 var e = (BlockExpression)expr;
|
|
871
|
|
872 Visit(e.Expressions, func);
|
|
873 Visit(e.Variables, func);
|
|
874
|
|
875 break;
|
|
876 }
|
|
877
|
|
878 #endif
|
|
879
|
|
880 case (ExpressionType)ChangeTypeExpression.ChangeTypeType :
|
|
881 Visit(((ChangeTypeExpression)expr).Expression, func); break;
|
|
882 }
|
|
883
|
|
884 func(expr);
|
|
885 }
|
|
886
|
|
887 static void Visit<T>(IEnumerable<T> source, Func<T,bool> func)
|
|
888 {
|
|
889 foreach (var item in source)
|
|
890 func(item);
|
|
891 }
|
|
892
|
|
893 static void Visit<T>(IEnumerable<T> source, Func<Expression,bool> func)
|
|
894 where T : Expression
|
|
895 {
|
|
896 foreach (var item in source)
|
|
897 Visit(item, func);
|
|
898 }
|
|
899
|
|
900 public static void Visit(this Expression expr, Func<Expression,bool> func)
|
|
901 {
|
|
902 if (expr == null || !func(expr))
|
|
903 return;
|
|
904
|
|
905 switch (expr.NodeType)
|
|
906 {
|
|
907 case ExpressionType.Add:
|
|
908 case ExpressionType.AddChecked:
|
|
909 case ExpressionType.And:
|
|
910 case ExpressionType.AndAlso:
|
|
911 case ExpressionType.ArrayIndex:
|
|
912 #if FW4 || SILVERLIGHT
|
|
913 case ExpressionType.Assign:
|
|
914 #endif
|
|
915 case ExpressionType.Coalesce:
|
|
916 case ExpressionType.Divide:
|
|
917 case ExpressionType.Equal:
|
|
918 case ExpressionType.ExclusiveOr:
|
|
919 case ExpressionType.GreaterThan:
|
|
920 case ExpressionType.GreaterThanOrEqual:
|
|
921 case ExpressionType.LeftShift:
|
|
922 case ExpressionType.LessThan:
|
|
923 case ExpressionType.LessThanOrEqual:
|
|
924 case ExpressionType.Modulo:
|
|
925 case ExpressionType.Multiply:
|
|
926 case ExpressionType.MultiplyChecked:
|
|
927 case ExpressionType.NotEqual:
|
|
928 case ExpressionType.Or:
|
|
929 case ExpressionType.OrElse:
|
|
930 case ExpressionType.Power:
|
|
931 case ExpressionType.RightShift:
|
|
932 case ExpressionType.Subtract:
|
|
933 case ExpressionType.SubtractChecked:
|
|
934 {
|
|
935 var e = (BinaryExpression)expr;
|
|
936
|
|
937 Visit(e.Conversion, func);
|
|
938 Visit(e.Left, func);
|
|
939 Visit(e.Right, func);
|
|
940
|
|
941 break;
|
|
942 }
|
|
943
|
|
944 case ExpressionType.ArrayLength:
|
|
945 case ExpressionType.Convert:
|
|
946 case ExpressionType.ConvertChecked:
|
|
947 case ExpressionType.Negate:
|
|
948 case ExpressionType.NegateChecked:
|
|
949 case ExpressionType.Not:
|
|
950 case ExpressionType.Quote:
|
|
951 case ExpressionType.TypeAs:
|
|
952 case ExpressionType.UnaryPlus:
|
|
953 Visit(((UnaryExpression)expr).Operand, func);
|
|
954 break;
|
|
955
|
|
956 case ExpressionType.Call:
|
|
957 {
|
|
958 var e = (MethodCallExpression)expr;
|
|
959
|
|
960 Visit(e.Object, func);
|
|
961 Visit(e.Arguments, func);
|
|
962
|
|
963 break;
|
|
964 }
|
|
965
|
|
966 case ExpressionType.Conditional:
|
|
967 {
|
|
968 var e = (ConditionalExpression)expr;
|
|
969
|
|
970 Visit(e.Test, func);
|
|
971 Visit(e.IfTrue, func);
|
|
972 Visit(e.IfFalse, func);
|
|
973
|
|
974 break;
|
|
975 }
|
|
976
|
|
977 case ExpressionType.Invoke:
|
|
978 {
|
|
979 var e = (InvocationExpression)expr;
|
|
980
|
|
981 Visit(e.Expression, func);
|
|
982 Visit(e.Arguments, func);
|
|
983
|
|
984 break;
|
|
985 }
|
|
986
|
|
987 case ExpressionType.Lambda:
|
|
988 {
|
|
989 var e = (LambdaExpression)expr;
|
|
990
|
|
991 Visit(e.Body, func);
|
|
992 Visit(e.Parameters, func);
|
|
993
|
|
994 break;
|
|
995 }
|
|
996
|
|
997 case ExpressionType.ListInit:
|
|
998 {
|
|
999 var e = (ListInitExpression)expr;
|
|
1000
|
|
1001 Visit(e.NewExpression, func);
|
|
1002 Visit(e.Initializers, ex => Visit(ex.Arguments, func));
|
|
1003
|
|
1004 break;
|
|
1005 }
|
|
1006
|
|
1007 case ExpressionType.MemberAccess: Visit(((MemberExpression)expr).Expression, func); break;
|
|
1008
|
|
1009 case ExpressionType.MemberInit:
|
|
1010 {
|
|
1011 Func<MemberBinding,bool> modify = null; modify = b =>
|
|
1012 {
|
|
1013 switch (b.BindingType)
|
|
1014 {
|
|
1015 case MemberBindingType.Assignment : Visit(((MemberAssignment)b). Expression, func); break;
|
|
1016 case MemberBindingType.ListBinding : Visit(((MemberListBinding)b).Initializers, p => Visit(p.Arguments, func)); break;
|
|
1017 case MemberBindingType.MemberBinding : Visit(((MemberMemberBinding)b).Bindings, modify); break;
|
|
1018 }
|
|
1019
|
|
1020 return true;
|
|
1021 };
|
|
1022
|
|
1023 var e = (MemberInitExpression)expr;
|
|
1024
|
|
1025 Visit(e.NewExpression, func);
|
|
1026 Visit(e.Bindings, modify);
|
|
1027
|
|
1028 break;
|
|
1029 }
|
|
1030
|
|
1031 case ExpressionType.New : Visit(((NewExpression) expr).Arguments, func); break;
|
|
1032 case ExpressionType.NewArrayBounds : Visit(((NewArrayExpression) expr).Expressions, func); break;
|
|
1033 case ExpressionType.NewArrayInit : Visit(((NewArrayExpression) expr).Expressions, func); break;
|
|
1034 case ExpressionType.TypeIs : Visit(((TypeBinaryExpression)expr).Expression, func); break;
|
|
1035
|
|
1036 #if FW4 || SILVERLIGHT
|
|
1037
|
|
1038 case ExpressionType.Block:
|
|
1039 {
|
|
1040 var e = (BlockExpression)expr;
|
|
1041
|
|
1042 Visit(e.Expressions, func);
|
|
1043 Visit(e.Variables, func);
|
|
1044
|
|
1045 break;
|
|
1046 }
|
|
1047
|
|
1048 #endif
|
|
1049
|
|
1050 case (ExpressionType)ChangeTypeExpression.ChangeTypeType :
|
|
1051 Visit(((ChangeTypeExpression)expr).Expression, func);
|
|
1052 break;
|
|
1053 }
|
|
1054 }
|
|
1055
|
|
1056 #endregion
|
|
1057
|
|
1058 #region Find
|
|
1059
|
|
1060 static Expression Find<T>(IEnumerable<T> source, Func<T,Expression> func)
|
|
1061 {
|
|
1062 foreach (var item in source)
|
|
1063 {
|
|
1064 var ex = func(item);
|
|
1065 if (ex != null)
|
|
1066 return ex;
|
|
1067 }
|
|
1068
|
|
1069 return null;
|
|
1070 }
|
|
1071
|
|
1072 static Expression Find<T>(IEnumerable<T> source, Func<Expression,bool> func)
|
|
1073 where T : Expression
|
|
1074 {
|
|
1075 foreach (var item in source)
|
|
1076 {
|
|
1077 var f = Find(item, func);
|
|
1078 if (f != null)
|
|
1079 return f;
|
|
1080 }
|
|
1081
|
|
1082 return null;
|
|
1083 }
|
|
1084
|
|
1085 public static Expression Find(this Expression expr, Func<Expression,bool> func)
|
|
1086 {
|
|
1087 if (expr == null || func(expr))
|
|
1088 return expr;
|
|
1089
|
|
1090 switch (expr.NodeType)
|
|
1091 {
|
|
1092 case ExpressionType.Add:
|
|
1093 case ExpressionType.AddChecked:
|
|
1094 case ExpressionType.And:
|
|
1095 case ExpressionType.AndAlso:
|
|
1096 case ExpressionType.ArrayIndex:
|
|
1097 #if FW4 || SILVERLIGHT
|
|
1098 case ExpressionType.Assign:
|
|
1099 #endif
|
|
1100 case ExpressionType.Coalesce:
|
|
1101 case ExpressionType.Divide:
|
|
1102 case ExpressionType.Equal:
|
|
1103 case ExpressionType.ExclusiveOr:
|
|
1104 case ExpressionType.GreaterThan:
|
|
1105 case ExpressionType.GreaterThanOrEqual:
|
|
1106 case ExpressionType.LeftShift:
|
|
1107 case ExpressionType.LessThan:
|
|
1108 case ExpressionType.LessThanOrEqual:
|
|
1109 case ExpressionType.Modulo:
|
|
1110 case ExpressionType.Multiply:
|
|
1111 case ExpressionType.MultiplyChecked:
|
|
1112 case ExpressionType.NotEqual:
|
|
1113 case ExpressionType.Or:
|
|
1114 case ExpressionType.OrElse:
|
|
1115 case ExpressionType.Power:
|
|
1116 case ExpressionType.RightShift:
|
|
1117 case ExpressionType.Subtract:
|
|
1118 case ExpressionType.SubtractChecked:
|
|
1119 {
|
|
1120 var e = (BinaryExpression)expr;
|
|
1121
|
|
1122 return
|
|
1123 Find(e.Conversion, func) ??
|
|
1124 Find(e.Left, func) ??
|
|
1125 Find(e.Right, func);
|
|
1126 }
|
|
1127
|
|
1128 case ExpressionType.ArrayLength:
|
|
1129 case ExpressionType.Convert:
|
|
1130 case ExpressionType.ConvertChecked:
|
|
1131 case ExpressionType.Negate:
|
|
1132 case ExpressionType.NegateChecked:
|
|
1133 case ExpressionType.Not:
|
|
1134 case ExpressionType.Quote:
|
|
1135 case ExpressionType.TypeAs:
|
|
1136 case ExpressionType.UnaryPlus:
|
|
1137 return Find(((UnaryExpression)expr).Operand, func);
|
|
1138
|
|
1139 case ExpressionType.Call:
|
|
1140 {
|
|
1141 var e = (MethodCallExpression)expr;
|
|
1142
|
|
1143 return
|
|
1144 Find(e.Object, func) ??
|
|
1145 Find(e.Arguments, func);
|
|
1146 }
|
|
1147
|
|
1148 case ExpressionType.Conditional:
|
|
1149 {
|
|
1150 var e = (ConditionalExpression)expr;
|
|
1151
|
|
1152 return
|
|
1153 Find(e.Test, func) ??
|
|
1154 Find(e.IfTrue, func) ??
|
|
1155 Find(e.IfFalse, func);
|
|
1156 }
|
|
1157
|
|
1158 case ExpressionType.Invoke:
|
|
1159 {
|
|
1160 var e = (InvocationExpression)expr;
|
|
1161
|
|
1162 return
|
|
1163 Find(e.Expression, func) ??
|
|
1164 Find(e.Arguments, func);
|
|
1165 }
|
|
1166
|
|
1167 case ExpressionType.Lambda:
|
|
1168 {
|
|
1169 var e = (LambdaExpression)expr;
|
|
1170
|
|
1171 return
|
|
1172 Find(e.Body, func) ??
|
|
1173 Find(e.Parameters, func);
|
|
1174 }
|
|
1175
|
|
1176 case ExpressionType.ListInit:
|
|
1177 {
|
|
1178 var e = (ListInitExpression)expr;
|
|
1179
|
|
1180 return
|
|
1181 Find(e.NewExpression, func) ??
|
|
1182 Find(e.Initializers, ex => Find(ex.Arguments, func));
|
|
1183 }
|
|
1184
|
|
1185 case ExpressionType.MemberAccess:
|
|
1186 return Find(((MemberExpression)expr).Expression, func);
|
|
1187
|
|
1188 case ExpressionType.MemberInit:
|
|
1189 {
|
|
1190 Func<MemberBinding,Expression> modify = null; modify = b =>
|
|
1191 {
|
|
1192 switch (b.BindingType)
|
|
1193 {
|
|
1194 case MemberBindingType.Assignment : return Find(((MemberAssignment)b). Expression, func);
|
|
1195 case MemberBindingType.ListBinding : return Find(((MemberListBinding)b). Initializers, p => Find(p.Arguments, func));
|
|
1196 case MemberBindingType.MemberBinding : return Find(((MemberMemberBinding)b).Bindings, modify);
|
|
1197 }
|
|
1198
|
|
1199 return null;
|
|
1200 };
|
|
1201
|
|
1202 var e = (MemberInitExpression)expr;
|
|
1203
|
|
1204 return
|
|
1205 Find(e.NewExpression, func) ??
|
|
1206 Find(e.Bindings, modify);
|
|
1207 }
|
|
1208
|
|
1209 case ExpressionType.New : return Find(((NewExpression) expr).Arguments, func);
|
|
1210 case ExpressionType.NewArrayBounds : return Find(((NewArrayExpression) expr).Expressions, func);
|
|
1211 case ExpressionType.NewArrayInit : return Find(((NewArrayExpression) expr).Expressions, func);
|
|
1212 case ExpressionType.TypeIs : return Find(((TypeBinaryExpression)expr).Expression, func);
|
|
1213
|
|
1214 #if FW4 || SILVERLIGHT
|
|
1215
|
|
1216 case ExpressionType.Block:
|
|
1217 {
|
|
1218 var e = (BlockExpression)expr;
|
|
1219
|
|
1220 return
|
|
1221 Find(e.Expressions, func) ??
|
|
1222 Find(e.Variables, func);
|
|
1223 }
|
|
1224
|
|
1225 #endif
|
|
1226
|
|
1227 case (ExpressionType)ChangeTypeExpression.ChangeTypeType :
|
|
1228 return Find(((ChangeTypeExpression)expr).Expression, func);
|
|
1229 }
|
|
1230
|
|
1231 return null;
|
|
1232 }
|
|
1233
|
|
1234 #endregion
|
|
1235
|
|
1236 #region Convert
|
|
1237
|
|
1238 static IEnumerable<T> Convert<T>(IEnumerable<T> source, Func<T,T> func)
|
|
1239 where T : class
|
|
1240 {
|
|
1241 var modified = false;
|
|
1242 var list = new List<T>();
|
|
1243
|
|
1244 foreach (var item in source)
|
|
1245 {
|
|
1246 var e = func(item);
|
|
1247 list.Add(e);
|
|
1248 modified = modified || e != item;
|
|
1249 }
|
|
1250
|
|
1251 return modified ? list : source;
|
|
1252 }
|
|
1253
|
|
1254 static IEnumerable<T> Convert<T>(IEnumerable<T> source, Func<Expression,Expression> func)
|
|
1255 where T : Expression
|
|
1256 {
|
|
1257 var modified = false;
|
|
1258 var list = new List<T>();
|
|
1259
|
|
1260 foreach (var item in source)
|
|
1261 {
|
|
1262 var e = Convert(item, func);
|
|
1263 list.Add((T)e);
|
|
1264 modified = modified || e != item;
|
|
1265 }
|
|
1266
|
|
1267 return modified? list: source;
|
|
1268 }
|
|
1269
|
|
1270 public static Expression Convert(this Expression expr, Func<Expression,Expression> func)
|
|
1271 {
|
|
1272 if (expr == null)
|
|
1273 return null;
|
|
1274
|
|
1275 switch (expr.NodeType)
|
|
1276 {
|
|
1277 case ExpressionType.Add:
|
|
1278 case ExpressionType.AddChecked:
|
|
1279 case ExpressionType.And:
|
|
1280 case ExpressionType.AndAlso:
|
|
1281 case ExpressionType.ArrayIndex:
|
|
1282 #if FW4 || SILVERLIGHT
|
|
1283 case ExpressionType.Assign:
|
|
1284 #endif
|
|
1285 case ExpressionType.Coalesce:
|
|
1286 case ExpressionType.Divide:
|
|
1287 case ExpressionType.Equal:
|
|
1288 case ExpressionType.ExclusiveOr:
|
|
1289 case ExpressionType.GreaterThan:
|
|
1290 case ExpressionType.GreaterThanOrEqual:
|
|
1291 case ExpressionType.LeftShift:
|
|
1292 case ExpressionType.LessThan:
|
|
1293 case ExpressionType.LessThanOrEqual:
|
|
1294 case ExpressionType.Modulo:
|
|
1295 case ExpressionType.Multiply:
|
|
1296 case ExpressionType.MultiplyChecked:
|
|
1297 case ExpressionType.NotEqual:
|
|
1298 case ExpressionType.Or:
|
|
1299 case ExpressionType.OrElse:
|
|
1300 case ExpressionType.Power:
|
|
1301 case ExpressionType.RightShift:
|
|
1302 case ExpressionType.Subtract:
|
|
1303 case ExpressionType.SubtractChecked:
|
|
1304 {
|
|
1305 var ex = func(expr);
|
|
1306 if (ex != expr)
|
|
1307 return ex;
|
|
1308
|
|
1309 var e = (BinaryExpression)expr;
|
|
1310 var c = Convert(e.Conversion, func);
|
|
1311 var l = Convert(e.Left, func);
|
|
1312 var r = Convert(e.Right, func);
|
|
1313
|
|
1314 #if FW3
|
|
1315 return c != e.Conversion || l != e.Left || r != e.Right ?
|
|
1316 Expression.MakeBinary(expr.NodeType, l, r, e.IsLiftedToNull, e.Method, (LambdaExpression)c):
|
|
1317 expr;
|
|
1318 #else
|
|
1319 return e.Update(l, (LambdaExpression)c, r);
|
|
1320 #endif
|
|
1321 }
|
|
1322
|
|
1323 case ExpressionType.ArrayLength:
|
|
1324 case ExpressionType.Convert:
|
|
1325 case ExpressionType.ConvertChecked:
|
|
1326 case ExpressionType.Negate:
|
|
1327 case ExpressionType.NegateChecked:
|
|
1328 case ExpressionType.Not:
|
|
1329 case ExpressionType.Quote:
|
|
1330 case ExpressionType.TypeAs:
|
|
1331 case ExpressionType.UnaryPlus:
|
|
1332 {
|
|
1333 var ex = func(expr);
|
|
1334 if (ex != expr)
|
|
1335 return ex;
|
|
1336
|
|
1337 var e = (UnaryExpression)expr;
|
|
1338 var o = Convert(e.Operand, func);
|
|
1339
|
|
1340 #if FW3
|
|
1341 return o != e.Operand ?
|
|
1342 Expression.MakeUnary(expr.NodeType, o, e.Type, e.Method) :
|
|
1343 expr;
|
|
1344 #else
|
|
1345 return e.Update(o);
|
|
1346 #endif
|
|
1347 }
|
|
1348
|
|
1349 case ExpressionType.Call:
|
|
1350 {
|
|
1351 var ex = func(expr);
|
|
1352 if (ex != expr)
|
|
1353 return ex;
|
|
1354
|
|
1355 var e = (MethodCallExpression)expr;
|
|
1356 var o = Convert(e.Object, func);
|
|
1357 var a = Convert(e.Arguments, func);
|
|
1358
|
|
1359 #if FW3
|
|
1360 return o != e.Object || a != e.Arguments ?
|
|
1361 Expression.Call(o, e.Method, a) :
|
|
1362 expr;
|
|
1363 #else
|
|
1364 return e.Update(o, a);
|
|
1365 #endif
|
|
1366 }
|
|
1367
|
|
1368 case ExpressionType.Conditional:
|
|
1369 {
|
|
1370 var ex = func(expr);
|
|
1371 if (ex != expr)
|
|
1372 return ex;
|
|
1373
|
|
1374 var e = (ConditionalExpression)expr;
|
|
1375 var s = Convert(e.Test, func);
|
|
1376 var t = Convert(e.IfTrue, func);
|
|
1377 var f = Convert(e.IfFalse, func);
|
|
1378
|
|
1379 #if FW3
|
|
1380 return s != e.Test || t != e.IfTrue || f != e.IfFalse ?
|
|
1381 Expression.Condition(s, t, f) :
|
|
1382 expr;
|
|
1383 #else
|
|
1384 return e.Update(s, t, f);
|
|
1385 #endif
|
|
1386 }
|
|
1387
|
|
1388 case ExpressionType.Invoke:
|
|
1389 {
|
|
1390 var exp = func(expr);
|
|
1391 if (exp != expr)
|
|
1392 return exp;
|
|
1393
|
|
1394 var e = (InvocationExpression)expr;
|
|
1395 var ex = Convert(e.Expression, func);
|
|
1396 var a = Convert(e.Arguments, func);
|
|
1397
|
|
1398 #if FW3
|
|
1399 return ex != e.Expression || a != e.Arguments ? Expression.Invoke(ex, a) : expr;
|
|
1400 #else
|
|
1401 return e.Update(ex, a);
|
|
1402 #endif
|
|
1403 }
|
|
1404
|
|
1405 case ExpressionType.Lambda:
|
|
1406 {
|
|
1407 var ex = func(expr);
|
|
1408 if (ex != expr)
|
|
1409 return ex;
|
|
1410
|
|
1411 var e = (LambdaExpression)expr;
|
|
1412 var b = Convert(e.Body, func);
|
|
1413 var p = Convert(e.Parameters, func);
|
|
1414
|
|
1415 return b != e.Body || p != e.Parameters ? Expression.Lambda(ex.Type, b, p.ToArray()) : expr;
|
|
1416 }
|
|
1417
|
|
1418 case ExpressionType.ListInit:
|
|
1419 {
|
|
1420 var ex = func(expr);
|
|
1421 if (ex != expr)
|
|
1422 return ex;
|
|
1423
|
|
1424 var e = (ListInitExpression)expr;
|
|
1425 var n = Convert(e.NewExpression, func);
|
|
1426 var i = Convert(e.Initializers, p =>
|
|
1427 {
|
|
1428 var args = Convert(p.Arguments, func);
|
|
1429 return args != p.Arguments? Expression.ElementInit(p.AddMethod, args): p;
|
|
1430 });
|
|
1431
|
|
1432 #if FW3
|
|
1433 return n != e.NewExpression || i != e.Initializers ?
|
|
1434 Expression.ListInit((NewExpression)n, i) :
|
|
1435 expr;
|
|
1436 #else
|
|
1437 return e.Update((NewExpression)n, i);
|
|
1438 #endif
|
|
1439 }
|
|
1440
|
|
1441 case ExpressionType.MemberAccess:
|
|
1442 {
|
|
1443 var exp = func(expr);
|
|
1444 if (exp != expr)
|
|
1445 return exp;
|
|
1446
|
|
1447 var e = (MemberExpression)expr;
|
|
1448 var ex = Convert(e.Expression, func);
|
|
1449
|
|
1450 #if FW3
|
|
1451 return ex != e.Expression ? Expression.MakeMemberAccess(ex, e.Member) : expr;
|
|
1452 #else
|
|
1453 return e.Update(ex);
|
|
1454 #endif
|
|
1455 }
|
|
1456
|
|
1457 case ExpressionType.MemberInit:
|
|
1458 {
|
|
1459 var exp = func(expr);
|
|
1460 if (exp != expr)
|
|
1461 return exp;
|
|
1462
|
|
1463 Func<MemberBinding,MemberBinding> modify = null; modify = b =>
|
|
1464 {
|
|
1465 switch (b.BindingType)
|
|
1466 {
|
|
1467 case MemberBindingType.Assignment:
|
|
1468 {
|
|
1469 var ma = (MemberAssignment)b;
|
|
1470 var ex = Convert(ma.Expression, func);
|
|
1471
|
|
1472 if (ex != ma.Expression)
|
|
1473 ma = Expression.Bind(ma.Member, ex);
|
|
1474
|
|
1475 return ma;
|
|
1476 }
|
|
1477
|
|
1478 case MemberBindingType.ListBinding:
|
|
1479 {
|
|
1480 var ml = (MemberListBinding)b;
|
|
1481 var i = Convert(ml.Initializers, p =>
|
|
1482 {
|
|
1483 var args = Convert(p.Arguments, func);
|
|
1484 return args != p.Arguments? Expression.ElementInit(p.AddMethod, args): p;
|
|
1485 });
|
|
1486
|
|
1487 if (i != ml.Initializers)
|
|
1488 ml = Expression.ListBind(ml.Member, i);
|
|
1489
|
|
1490 return ml;
|
|
1491 }
|
|
1492
|
|
1493 case MemberBindingType.MemberBinding:
|
|
1494 {
|
|
1495 var mm = (MemberMemberBinding)b;
|
|
1496 var bs = Convert(mm.Bindings, modify);
|
|
1497
|
|
1498 if (bs != mm.Bindings)
|
|
1499 mm = Expression.MemberBind(mm.Member);
|
|
1500
|
|
1501 return mm;
|
|
1502 }
|
|
1503 }
|
|
1504
|
|
1505 return b;
|
|
1506 };
|
|
1507
|
|
1508 var e = (MemberInitExpression)expr;
|
|
1509 var ne = Convert(e.NewExpression, func);
|
|
1510 var bb = Convert(e.Bindings, modify);
|
|
1511
|
|
1512 #if FW3
|
|
1513 return ne != e.NewExpression || bb != e.Bindings ?
|
|
1514 Expression.MemberInit((NewExpression)ne, bb) :
|
|
1515 expr;
|
|
1516 #else
|
|
1517 return e.Update((NewExpression)ne, bb);
|
|
1518 #endif
|
|
1519 }
|
|
1520
|
|
1521 case ExpressionType.New:
|
|
1522 {
|
|
1523 var ex = func(expr);
|
|
1524 if (ex != expr)
|
|
1525 return ex;
|
|
1526
|
|
1527 var e = (NewExpression)expr;
|
|
1528 var a = Convert(e.Arguments, func);
|
|
1529
|
|
1530 #if FW3
|
|
1531 return a != e.Arguments ?
|
|
1532 e.Members == null ?
|
|
1533 Expression.New(e.Constructor, a) :
|
|
1534 Expression.New(e.Constructor, a, e.Members) :
|
|
1535 expr;
|
|
1536 #else
|
|
1537 return e.Update(a);
|
|
1538 #endif
|
|
1539 }
|
|
1540
|
|
1541 case ExpressionType.NewArrayBounds:
|
|
1542 {
|
|
1543 var exp = func(expr);
|
|
1544 if (exp != expr)
|
|
1545 return exp;
|
|
1546
|
|
1547 var e = (NewArrayExpression)expr;
|
|
1548 var ex = Convert(e.Expressions, func);
|
|
1549
|
|
1550 #if FW3
|
|
1551 return ex != e.Expressions ? Expression.NewArrayBounds(e.Type, ex) : expr;
|
|
1552 #else
|
|
1553 return e.Update(ex);
|
|
1554 #endif
|
|
1555 }
|
|
1556
|
|
1557 case ExpressionType.NewArrayInit:
|
|
1558 {
|
|
1559 var exp = func(expr);
|
|
1560 if (exp != expr)
|
|
1561 return exp;
|
|
1562
|
|
1563 var e = (NewArrayExpression)expr;
|
|
1564 var ex = Convert(e.Expressions, func);
|
|
1565
|
|
1566 #if FW3
|
|
1567 return ex != e.Expressions ?
|
|
1568 Expression.NewArrayInit(e.Type.GetElementType(), ex) :
|
|
1569 expr;
|
|
1570 #else
|
|
1571 return e.Update(ex);
|
|
1572
|
|
1573 #endif
|
|
1574 }
|
|
1575
|
|
1576 case ExpressionType.TypeIs:
|
|
1577 {
|
|
1578 var exp = func(expr);
|
|
1579 if (exp != expr)
|
|
1580 return exp;
|
|
1581
|
|
1582 var e = (TypeBinaryExpression)expr;
|
|
1583 var ex = Convert(e.Expression, func);
|
|
1584
|
|
1585 #if FW3
|
|
1586 return ex != e.Expression ? Expression.TypeIs(ex, e.Type) : expr;
|
|
1587 #else
|
|
1588 return e.Update(ex);
|
|
1589 #endif
|
|
1590 }
|
|
1591
|
|
1592 #if FW4 || SILVERLIGHT
|
|
1593
|
|
1594 case ExpressionType.Block:
|
|
1595 {
|
|
1596 var exp = func(expr);
|
|
1597 if (exp != expr)
|
|
1598 return exp;
|
|
1599
|
|
1600 var e = (BlockExpression)expr;
|
|
1601 var ex = Convert(e.Expressions, func);
|
|
1602 var v = Convert(e.Variables, func);
|
|
1603
|
|
1604 return e.Update(v, ex);
|
|
1605 }
|
|
1606
|
|
1607 #endif
|
|
1608
|
|
1609 case ExpressionType.Constant : return func(expr);
|
|
1610 case ExpressionType.Parameter: return func(expr);
|
|
1611
|
|
1612 case (ExpressionType)ChangeTypeExpression.ChangeTypeType :
|
|
1613 {
|
|
1614 var exp = func(expr);
|
|
1615 if (exp != expr)
|
|
1616 return exp;
|
|
1617
|
|
1618 var e = expr as ChangeTypeExpression;
|
|
1619 var ex = Convert(e.Expression, func);
|
|
1620
|
|
1621 if (ex == e.Expression)
|
|
1622 return expr;
|
|
1623
|
|
1624 if (ex.Type == e.Type)
|
|
1625 return ex;
|
|
1626
|
|
1627 return new ChangeTypeExpression(ex, e.Type);
|
|
1628 }
|
|
1629 }
|
|
1630
|
|
1631 throw new InvalidOperationException();
|
|
1632 }
|
|
1633
|
|
1634 #endregion
|
|
1635
|
|
1636 #region Convert2
|
|
1637
|
|
1638 public struct ConvertInfo
|
|
1639 {
|
|
1640 public ConvertInfo(Expression expression, bool stop)
|
|
1641 {
|
|
1642 Expression = expression;
|
|
1643 Stop = stop;
|
|
1644 }
|
|
1645
|
|
1646 public ConvertInfo(Expression expression)
|
|
1647 {
|
|
1648 Expression = expression;
|
|
1649 Stop = false;
|
|
1650 }
|
|
1651
|
|
1652 public Expression Expression;
|
|
1653 public bool Stop;
|
|
1654 }
|
|
1655
|
|
1656 static IEnumerable<T> Convert2<T>(IEnumerable<T> source, Func<T,T> func)
|
|
1657 where T : class
|
|
1658 {
|
|
1659 var modified = false;
|
|
1660 var list = new List<T>();
|
|
1661
|
|
1662 foreach (var item in source)
|
|
1663 {
|
|
1664 var e = func(item);
|
|
1665 list.Add(e);
|
|
1666 modified = modified || e != item;
|
|
1667 }
|
|
1668
|
|
1669 return modified ? list : source;
|
|
1670 }
|
|
1671
|
|
1672 static IEnumerable<T> Convert2<T>(IEnumerable<T> source, Func<Expression,ConvertInfo> func)
|
|
1673 where T : Expression
|
|
1674 {
|
|
1675 var modified = false;
|
|
1676 var list = new List<T>();
|
|
1677
|
|
1678 foreach (var item in source)
|
|
1679 {
|
|
1680 var e = Convert2(item, func);
|
|
1681 list.Add((T)e);
|
|
1682 modified = modified || e != item;
|
|
1683 }
|
|
1684
|
|
1685 return modified ? list : source;
|
|
1686 }
|
|
1687
|
|
1688 #if FW3
|
|
1689 static IEnumerable<Expression> ConvertMethodArguments(IEnumerable<Expression> source, MethodBase method)
|
|
1690 {
|
|
1691 return ConvertMethodArguments(source, method, null);
|
|
1692 }
|
|
1693
|
|
1694 static IEnumerable<Expression> ConvertMethodArguments(IEnumerable<Expression> source, MethodBase method, IList<MemberInfo> initMembers)
|
|
1695 #else
|
|
1696 static IEnumerable<Expression> ConvertMethodArguments(IEnumerable<Expression> source, MethodBase method, IList<MemberInfo> initMembers = null)
|
|
1697 #endif
|
|
1698 {
|
|
1699 var list = new List<Expression>();
|
|
1700
|
|
1701 var targetTypes = new List<Type>();
|
|
1702 foreach (var param in method.GetParameters())
|
|
1703 {
|
|
1704 targetTypes.Add(param.ParameterType);
|
|
1705 }
|
|
1706 if (initMembers != null)
|
|
1707 {
|
|
1708 foreach (var mi in initMembers)
|
|
1709 {
|
|
1710 if (mi is PropertyInfo)
|
|
1711 {
|
|
1712 targetTypes.Add(((PropertyInfo)mi).PropertyType);
|
|
1713 }
|
|
1714 else if (mi is FieldInfo)
|
|
1715 {
|
|
1716 targetTypes.Add(((FieldInfo)mi).FieldType);
|
|
1717 }
|
|
1718 }
|
|
1719 }
|
|
1720
|
|
1721 var idx = 0;
|
|
1722 foreach (var item in source)
|
|
1723 {
|
|
1724 var targetType = targetTypes[idx];
|
|
1725 if (item.Type != targetType)
|
|
1726 {
|
|
1727 list.Add(Expression.Convert(item, targetType));
|
|
1728 }
|
|
1729 else
|
|
1730 {
|
|
1731 list.Add(item);
|
|
1732 }
|
|
1733 idx++;
|
|
1734 }
|
|
1735
|
|
1736 return list;
|
|
1737 }
|
|
1738
|
|
1739 public static Expression Convert2(this Expression expr, Func<Expression,ConvertInfo> func)
|
|
1740 {
|
|
1741 if (expr == null)
|
|
1742 return null;
|
|
1743
|
|
1744 ConvertInfo ci;
|
|
1745
|
|
1746 switch (expr.NodeType)
|
|
1747 {
|
|
1748 case ExpressionType.Add:
|
|
1749 case ExpressionType.AddChecked:
|
|
1750 case ExpressionType.And:
|
|
1751 case ExpressionType.AndAlso:
|
|
1752 case ExpressionType.ArrayIndex:
|
|
1753 #if FW4 || SILVERLIGHT
|
|
1754 case ExpressionType.Assign:
|
|
1755 #endif
|
|
1756 case ExpressionType.Coalesce:
|
|
1757 case ExpressionType.Divide:
|
|
1758 case ExpressionType.Equal:
|
|
1759 case ExpressionType.ExclusiveOr:
|
|
1760 case ExpressionType.GreaterThan:
|
|
1761 case ExpressionType.GreaterThanOrEqual:
|
|
1762 case ExpressionType.LeftShift:
|
|
1763 case ExpressionType.LessThan:
|
|
1764 case ExpressionType.LessThanOrEqual:
|
|
1765 case ExpressionType.Modulo:
|
|
1766 case ExpressionType.Multiply:
|
|
1767 case ExpressionType.MultiplyChecked:
|
|
1768 case ExpressionType.NotEqual:
|
|
1769 case ExpressionType.Or:
|
|
1770 case ExpressionType.OrElse:
|
|
1771 case ExpressionType.Power:
|
|
1772 case ExpressionType.RightShift:
|
|
1773 case ExpressionType.Subtract:
|
|
1774 case ExpressionType.SubtractChecked:
|
|
1775 {
|
|
1776 ci = func(expr);
|
|
1777 if (ci.Stop || ci.Expression != expr)
|
|
1778 return ci.Expression;
|
|
1779
|
|
1780 var e = expr as BinaryExpression;
|
|
1781 var c = Convert2(e.Conversion, func);
|
|
1782 var l = Convert2(e.Left, func);
|
|
1783 var r = Convert2(e.Right, func);
|
|
1784
|
|
1785 return c != e.Conversion || l != e.Left || r != e.Right ?
|
|
1786 Expression.MakeBinary(expr.NodeType, l, r, e.IsLiftedToNull, e.Method, (LambdaExpression)c):
|
|
1787 expr;
|
|
1788 }
|
|
1789
|
|
1790 case ExpressionType.ArrayLength:
|
|
1791 case ExpressionType.Convert:
|
|
1792 case ExpressionType.ConvertChecked:
|
|
1793 case ExpressionType.Negate:
|
|
1794 case ExpressionType.NegateChecked:
|
|
1795 case ExpressionType.Not:
|
|
1796 case ExpressionType.Quote:
|
|
1797 case ExpressionType.TypeAs:
|
|
1798 case ExpressionType.UnaryPlus:
|
|
1799 {
|
|
1800 ci = func(expr);
|
|
1801 if (ci.Stop || ci.Expression != expr)
|
|
1802 return ci.Expression;
|
|
1803
|
|
1804 var e = expr as UnaryExpression;
|
|
1805 var o = Convert2(e.Operand, func);
|
|
1806
|
|
1807 return o != e.Operand ?
|
|
1808 Expression.MakeUnary(expr.NodeType, o, e.Type, e.Method) :
|
|
1809 expr;
|
|
1810 }
|
|
1811
|
|
1812 case ExpressionType.Call:
|
|
1813 {
|
|
1814 ci = func(expr);
|
|
1815 if (ci.Stop || ci.Expression != expr)
|
|
1816 return ci.Expression;
|
|
1817
|
|
1818 var e = expr as MethodCallExpression;
|
|
1819 var o = Convert2(e.Object, func);
|
|
1820 var a = Convert2(e.Arguments, func);
|
|
1821
|
|
1822 return o != e.Object || a != e.Arguments ?
|
|
1823 Expression.Call(o, e.Method, ConvertMethodArguments(a, e.Method)) :
|
|
1824 expr;
|
|
1825 }
|
|
1826
|
|
1827 case ExpressionType.Conditional:
|
|
1828 {
|
|
1829 ci = func(expr);
|
|
1830 if (ci.Stop || ci.Expression != expr)
|
|
1831 return ci.Expression;
|
|
1832
|
|
1833 var e = expr as ConditionalExpression;
|
|
1834 var s = Convert2(e.Test, func);
|
|
1835 var t = Convert2(e.IfTrue, func);
|
|
1836 var f = Convert2(e.IfFalse, func);
|
|
1837
|
|
1838 return s != e.Test || t != e.IfTrue || f != e.IfFalse ?
|
|
1839 Expression.Condition(s, t, f) :
|
|
1840 expr;
|
|
1841 }
|
|
1842
|
|
1843 case ExpressionType.Invoke:
|
|
1844 {
|
|
1845 ci = func(expr);
|
|
1846 if (ci.Stop || ci.Expression != expr)
|
|
1847 return ci.Expression;
|
|
1848
|
|
1849 var e = expr as InvocationExpression;
|
|
1850 var ex = Convert2(e.Expression, func);
|
|
1851 var a = Convert2(e.Arguments, func);
|
|
1852
|
|
1853 return ex != e.Expression || a != e.Arguments ? Expression.Invoke(ex, a) : expr;
|
|
1854 }
|
|
1855
|
|
1856 case ExpressionType.Lambda:
|
|
1857 {
|
|
1858 ci = func(expr);
|
|
1859 if (ci.Stop || ci.Expression != expr)
|
|
1860 return ci.Expression;
|
|
1861
|
|
1862 var e = expr as LambdaExpression;
|
|
1863 var b = Convert2(e.Body, func);
|
|
1864 var p = Convert2(e.Parameters, func);
|
|
1865
|
|
1866 return b != e.Body || p != e.Parameters ? Expression.Lambda(ci.Expression.Type, b, p.ToArray()) : expr;
|
|
1867 }
|
|
1868
|
|
1869 case ExpressionType.ListInit:
|
|
1870 {
|
|
1871 ci = func(expr);
|
|
1872 if (ci.Stop || ci.Expression != expr)
|
|
1873 return ci.Expression;
|
|
1874
|
|
1875 var e = expr as ListInitExpression;
|
|
1876 var n = Convert2(e.NewExpression, func);
|
|
1877 var i = Convert2(e.Initializers, p =>
|
|
1878 {
|
|
1879 var args = Convert2(p.Arguments, func);
|
|
1880 return args != p.Arguments? Expression.ElementInit(p.AddMethod, args): p;
|
|
1881 });
|
|
1882
|
|
1883 return n != e.NewExpression || i != e.Initializers ?
|
|
1884 Expression.ListInit((NewExpression)n, i) :
|
|
1885 expr;
|
|
1886 }
|
|
1887
|
|
1888 case ExpressionType.MemberAccess:
|
|
1889 {
|
|
1890 ci = func(expr);
|
|
1891 if (ci.Stop || ci.Expression != expr)
|
|
1892 return ci.Expression;
|
|
1893
|
|
1894 var e = expr as MemberExpression;
|
|
1895 var ex = Convert2(e.Expression, func);
|
|
1896
|
|
1897 return ex != e.Expression ? Expression.MakeMemberAccess(ex, e.Member) : expr;
|
|
1898 }
|
|
1899
|
|
1900 case ExpressionType.MemberInit:
|
|
1901 {
|
|
1902 ci = func(expr);
|
|
1903 if (ci.Stop || ci.Expression != expr)
|
|
1904 return ci.Expression;
|
|
1905
|
|
1906 Func<MemberBinding,MemberBinding> modify = null; modify = b =>
|
|
1907 {
|
|
1908 switch (b.BindingType)
|
|
1909 {
|
|
1910 case MemberBindingType.Assignment:
|
|
1911 {
|
|
1912 var ma = (MemberAssignment)b;
|
|
1913 var ex = Convert2(ma.Expression, func);
|
|
1914
|
|
1915 if (ex != ma.Expression)
|
|
1916 {
|
|
1917 if (ex.Type != ma.Expression.Type)
|
|
1918 {
|
|
1919 ex = Expression.Convert(ex, ma.Expression.Type);
|
|
1920 }
|
|
1921 ma = Expression.Bind(ma.Member, ex);
|
|
1922 }
|
|
1923
|
|
1924 return ma;
|
|
1925 }
|
|
1926
|
|
1927 case MemberBindingType.ListBinding:
|
|
1928 {
|
|
1929 var ml = (MemberListBinding)b;
|
|
1930 var i = Convert(ml.Initializers, p =>
|
|
1931 {
|
|
1932 var args = Convert2(p.Arguments, func);
|
|
1933 return args != p.Arguments? Expression.ElementInit(p.AddMethod, args): p;
|
|
1934 });
|
|
1935
|
|
1936 if (i != ml.Initializers)
|
|
1937 ml = Expression.ListBind(ml.Member, i);
|
|
1938
|
|
1939 return ml;
|
|
1940 }
|
|
1941
|
|
1942 case MemberBindingType.MemberBinding:
|
|
1943 {
|
|
1944 var mm = (MemberMemberBinding)b;
|
|
1945 var bs = Convert(mm.Bindings, modify);
|
|
1946
|
|
1947 if (bs != mm.Bindings)
|
|
1948 mm = Expression.MemberBind(mm.Member);
|
|
1949
|
|
1950 return mm;
|
|
1951 }
|
|
1952 }
|
|
1953
|
|
1954 return b;
|
|
1955 };
|
|
1956
|
|
1957 var e = expr as MemberInitExpression;
|
|
1958 var ne = Convert2(e.NewExpression, func);
|
|
1959 var bb = Convert2(e.Bindings, modify);
|
|
1960
|
|
1961 return ne != e.NewExpression || bb != e.Bindings ?
|
|
1962 Expression.MemberInit((NewExpression)ne, bb) :
|
|
1963 expr;
|
|
1964 }
|
|
1965
|
|
1966 case ExpressionType.New:
|
|
1967 {
|
|
1968 ci = func(expr);
|
|
1969 if (ci.Stop || ci.Expression != expr)
|
|
1970 return ci.Expression;
|
|
1971
|
|
1972 var e = expr as NewExpression;
|
|
1973 var a = Convert2(e.Arguments, func);
|
|
1974
|
|
1975 return a != e.Arguments ?
|
|
1976 e.Members == null ?
|
|
1977 Expression.New(e.Constructor, ConvertMethodArguments(a, e.Constructor)) :
|
|
1978 Expression.New(e.Constructor, ConvertMethodArguments(a, e.Constructor, e.Members), e.Members) :
|
|
1979 expr;
|
|
1980 }
|
|
1981
|
|
1982 case ExpressionType.NewArrayBounds:
|
|
1983 {
|
|
1984 ci = func(expr);
|
|
1985 if (ci.Stop || ci.Expression != expr)
|
|
1986 return ci.Expression;
|
|
1987
|
|
1988 var e = expr as NewArrayExpression;
|
|
1989 var ex = Convert2(e.Expressions, func);
|
|
1990
|
|
1991 return ex != e.Expressions ? Expression.NewArrayBounds(e.Type, ex) : expr;
|
|
1992 }
|
|
1993
|
|
1994 case ExpressionType.NewArrayInit:
|
|
1995 {
|
|
1996 ci = func(expr);
|
|
1997 if (ci.Stop || ci.Expression != expr)
|
|
1998 return ci.Expression;
|
|
1999
|
|
2000 var e = expr as NewArrayExpression;
|
|
2001 var et = e.Type.GetElementType();
|
|
2002 var ex = Convert2(e.Expressions, func)
|
|
2003 .Select(ee => et == typeof(object) && ee.Type.IsValueType ?
|
|
2004 Expression.Convert(ee, typeof(object)) :
|
|
2005 ee);
|
|
2006
|
|
2007 return ex != e.Expressions ?
|
|
2008 Expression.NewArrayInit(et, ex) :
|
|
2009 expr;
|
|
2010 }
|
|
2011
|
|
2012 case ExpressionType.TypeIs :
|
|
2013 {
|
|
2014 ci = func(expr);
|
|
2015 if (ci.Stop || ci.Expression != expr)
|
|
2016 return ci.Expression;
|
|
2017
|
|
2018 var e = expr as TypeBinaryExpression;
|
|
2019 var ex = Convert2(e.Expression, func);
|
|
2020
|
|
2021 return ex != e.Expression ? Expression.TypeIs(ex, e.Type) : expr;
|
|
2022 }
|
|
2023
|
|
2024 #if FW4 || SILVERLIGHT
|
|
2025
|
|
2026 case ExpressionType.Block :
|
|
2027 {
|
|
2028 ci = func(expr);
|
|
2029 if (ci.Stop || ci.Expression != expr)
|
|
2030 return ci.Expression;
|
|
2031
|
|
2032 var e = expr as BlockExpression;
|
|
2033 var ex = Convert2(e.Expressions, func);
|
|
2034 var v = Convert2(e.Variables, func);
|
|
2035
|
|
2036 return ex != e.Expressions || v != e.Variables ? Expression.Block(e.Type, v, ex) : expr;
|
|
2037 }
|
|
2038
|
|
2039 #endif
|
|
2040
|
|
2041 case ExpressionType.Constant : return func(expr).Expression;
|
|
2042 case ExpressionType.Parameter: return func(expr).Expression;
|
|
2043
|
|
2044 case (ExpressionType)ChangeTypeExpression.ChangeTypeType :
|
|
2045 {
|
|
2046 ci = func(expr);
|
|
2047 if (ci.Stop || ci.Expression != expr)
|
|
2048 return ci.Expression;
|
|
2049
|
|
2050 var e = expr as ChangeTypeExpression;
|
|
2051 var ex = Convert2(e.Expression, func);
|
|
2052
|
|
2053 if (ex == e.Expression)
|
|
2054 return expr;
|
|
2055
|
|
2056 if (ex.Type == e.Type)
|
|
2057 return ex;
|
|
2058
|
|
2059 return new ChangeTypeExpression(ex, e.Type);
|
|
2060 }
|
|
2061 }
|
|
2062
|
|
2063 throw new InvalidOperationException();
|
|
2064 }
|
|
2065
|
|
2066 #endregion
|
|
2067
|
|
2068 #region Helpers
|
|
2069
|
|
2070 static public Expression Unwrap(this Expression ex)
|
|
2071 {
|
|
2072 if (ex == null)
|
|
2073 return null;
|
|
2074
|
|
2075 switch (ex.NodeType)
|
|
2076 {
|
|
2077 case ExpressionType.Quote : return ((UnaryExpression)ex).Operand.Unwrap();
|
|
2078 case ExpressionType.ConvertChecked :
|
|
2079 case ExpressionType.Convert :
|
|
2080 {
|
|
2081 var ue = (UnaryExpression)ex;
|
|
2082
|
|
2083 if (!ue.Operand.Type.IsEnum)
|
|
2084 return ue.Operand.Unwrap();
|
|
2085
|
|
2086 break;
|
|
2087 }
|
|
2088 }
|
|
2089
|
|
2090 return ex;
|
|
2091 }
|
|
2092
|
|
2093 static public Dictionary<Expression,Expression> GetExpressionAccessors(this Expression expression, Expression path)
|
|
2094 {
|
|
2095 var accessors = new Dictionary<Expression,Expression>();
|
|
2096
|
|
2097 expression.Path(path, (e,p) =>
|
|
2098 {
|
|
2099 switch (e.NodeType)
|
|
2100 {
|
|
2101 case ExpressionType.Call :
|
|
2102 case ExpressionType.MemberAccess :
|
|
2103 case ExpressionType.New :
|
|
2104 if (!accessors.ContainsKey(e))
|
|
2105 accessors.Add(e, p);
|
|
2106 break;
|
|
2107
|
|
2108 case ExpressionType.Constant :
|
|
2109 if (!accessors.ContainsKey(e))
|
|
2110 accessors.Add(e, Expression.Property(p, ReflectionHelper.Constant.Value));
|
|
2111 break;
|
|
2112
|
|
2113 case ExpressionType.ConvertChecked :
|
|
2114 case ExpressionType.Convert :
|
|
2115 if (!accessors.ContainsKey(e))
|
|
2116 {
|
|
2117 var ue = (UnaryExpression)e;
|
|
2118
|
|
2119 switch (ue.Operand.NodeType)
|
|
2120 {
|
|
2121 case ExpressionType.Call :
|
|
2122 case ExpressionType.MemberAccess :
|
|
2123 case ExpressionType.New :
|
|
2124 case ExpressionType.Constant :
|
|
2125
|
|
2126 accessors.Add(e, p);
|
|
2127 break;
|
|
2128 }
|
|
2129 }
|
|
2130
|
|
2131 break;
|
|
2132 }
|
|
2133 });
|
|
2134
|
|
2135 return accessors;
|
|
2136 }
|
|
2137
|
|
2138 static public Expression GetRootObject(this Expression expr)
|
|
2139 {
|
|
2140 if (expr == null)
|
|
2141 return null;
|
|
2142
|
|
2143 switch (expr.NodeType)
|
|
2144 {
|
|
2145 case ExpressionType.Call :
|
|
2146 {
|
|
2147 var e = (MethodCallExpression)expr;
|
|
2148
|
|
2149 if (e.Object != null)
|
|
2150 return GetRootObject(e.Object);
|
|
2151
|
|
2152 if (e.Arguments != null && e.Arguments.Count > 0 && e.IsQueryable())
|
|
2153 return GetRootObject(e.Arguments[0]);
|
|
2154
|
|
2155 break;
|
|
2156 }
|
|
2157
|
|
2158 case ExpressionType.MemberAccess :
|
|
2159 {
|
|
2160 var e = (MemberExpression)expr;
|
|
2161
|
|
2162 if (e.Expression != null)
|
|
2163 return GetRootObject(e.Expression.Unwrap());
|
|
2164
|
|
2165 break;
|
|
2166 }
|
|
2167 }
|
|
2168
|
|
2169 return expr;
|
|
2170 }
|
|
2171
|
|
2172 static public List<Expression> GetMembers(this Expression expr)
|
|
2173 {
|
|
2174 if (expr == null)
|
|
2175 return new List<Expression>();
|
|
2176
|
|
2177 List<Expression> list;
|
|
2178
|
|
2179 switch (expr.NodeType)
|
|
2180 {
|
|
2181 case ExpressionType.Call :
|
|
2182 {
|
|
2183 var e = (MethodCallExpression)expr;
|
|
2184
|
|
2185 if (e.Object != null)
|
|
2186 list = GetMembers(e.Object);
|
|
2187 else if (e.Arguments != null && e.Arguments.Count > 0 && e.IsQueryable())
|
|
2188 list = GetMembers(e.Arguments[0]);
|
|
2189 else
|
|
2190 list = new List<Expression>();
|
|
2191
|
|
2192 break;
|
|
2193 }
|
|
2194
|
|
2195 case ExpressionType.MemberAccess :
|
|
2196 {
|
|
2197 var e = (MemberExpression)expr;
|
|
2198
|
|
2199 if (e.Expression != null)
|
|
2200 list = GetMembers(e.Expression.Unwrap());
|
|
2201 else
|
|
2202 list = new List<Expression>();
|
|
2203
|
|
2204 break;
|
|
2205 }
|
|
2206
|
|
2207 default :
|
|
2208 list = new List<Expression>();
|
|
2209 break;
|
|
2210 }
|
|
2211
|
|
2212 list.Add(expr);
|
|
2213
|
|
2214 return list;
|
|
2215 }
|
|
2216
|
|
2217 static public bool IsQueryable(this MethodCallExpression method)
|
|
2218 {
|
|
2219 var type = method.Method.DeclaringType;
|
|
2220
|
|
2221 return type == typeof(Queryable) || type == typeof(Enumerable) || type == typeof(LinqExtensions);
|
|
2222 }
|
|
2223
|
|
2224 static public bool IsQueryable(this MethodCallExpression method, string name)
|
|
2225 {
|
|
2226 return method.Method.Name == name && method.IsQueryable();
|
|
2227 }
|
|
2228
|
|
2229 static public bool IsQueryable(this MethodCallExpression method, params string[] names)
|
|
2230 {
|
|
2231 if (method.IsQueryable())
|
|
2232 foreach (var name in names)
|
|
2233 if (method.Method.Name == name)
|
|
2234 return true;
|
|
2235
|
|
2236 return false;
|
|
2237 }
|
|
2238
|
|
2239 static Expression FindLevel(Expression expression, int level, ref int current)
|
|
2240 {
|
|
2241 switch (expression.NodeType)
|
|
2242 {
|
|
2243 case ExpressionType.Call :
|
|
2244 {
|
|
2245 var call = (MethodCallExpression)expression;
|
|
2246 var expr = call.Object;
|
|
2247
|
|
2248 if (expr == null && call.IsQueryable() && call.Arguments.Count > 0)
|
|
2249 expr = call.Arguments[0];
|
|
2250
|
|
2251 if (expr != null)
|
|
2252 {
|
|
2253 var ex = FindLevel(expr, level, ref current);
|
|
2254
|
|
2255 if (level == current)
|
|
2256 return ex;
|
|
2257
|
|
2258 current++;
|
|
2259 }
|
|
2260
|
|
2261 break;
|
|
2262 }
|
|
2263
|
|
2264 case ExpressionType.MemberAccess:
|
|
2265 {
|
|
2266 var e = ((MemberExpression)expression);
|
|
2267
|
|
2268 if (e.Expression != null)
|
|
2269 {
|
|
2270 var expr = FindLevel(e.Expression.Unwrap(), level, ref current);
|
|
2271
|
|
2272 if (level == current)
|
|
2273 return expr;
|
|
2274
|
|
2275 current++;
|
|
2276 }
|
|
2277
|
|
2278 break;
|
|
2279 }
|
|
2280 }
|
|
2281
|
|
2282 return expression;
|
|
2283 }
|
|
2284
|
|
2285 static public Expression GetLevelExpression(this Expression expression, int level)
|
|
2286 {
|
|
2287 var current = 0;
|
|
2288 var expr = FindLevel(expression, level, ref current);
|
|
2289
|
|
2290 if (expr == null || current != level)
|
|
2291 throw new InvalidOperationException();
|
|
2292
|
|
2293 return expr;
|
|
2294 }
|
|
2295
|
|
2296 #endregion
|
|
2297 }
|
|
2298 }
|