comparison Source/Linq/ExpressionHelper.cs @ 0:f990fcb411a9

Копия текущей версии из github
author cin
date Thu, 27 Mar 2014 21:46:09 +0400
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:f990fcb411a9
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 }