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 } |
