Mercurial > pub > bltoolkit
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 } |