1 //----------------------------------------------------------------------------- 2 // Copyright (c) Microsoft Corporation. All rights reserved. 3 //----------------------------------------------------------------------------- 4 5 namespace System.Activities 6 { 7 using System; 8 using System.Collections.ObjectModel; 9 using System.ComponentModel; 10 using System.Linq; 11 using System.Linq.Expressions; 12 using System.Reflection; 13 using System.Runtime; 14 using System.Runtime.Serialization; 15 using System.Collections.Generic; 16 using System.Diagnostics.CodeAnalysis; 17 using System.Activities.XamlIntegration; 18 19 static class ExpressionUtilities 20 { 21 public static ParameterExpression RuntimeContextParameter = Expression.Parameter(typeof(ActivityContext), "context"); 22 static Assembly linqAssembly = typeof(Func<>).Assembly; 23 static MethodInfo createLocationFactoryGenericMethod = typeof(ExpressionUtilities).GetMethod("CreateLocationFactory"); 24 static MethodInfo propertyDescriptorGetValue; // PropertyDescriptor.GetValue 25 26 27 // Types cached for use in TryRewriteLambdaExpression 28 static Type inArgumentGenericType = typeof(InArgument<>); 29 static Type outArgumentGenericType = typeof(OutArgument<>); 30 static Type inOutArgumentGenericType = typeof(InOutArgument<>); 31 static Type variableGenericType = typeof(Variable<>); 32 static Type delegateInArgumentGenericType = typeof(DelegateInArgument<>); 33 static Type delegateOutArgumentGenericType = typeof(DelegateOutArgument<>); 34 static Type activityContextType = typeof(ActivityContext); 35 static Type locationReferenceType = typeof(LocationReference); 36 static Type runtimeArgumentType = typeof(RuntimeArgument); 37 static Type argumentType = typeof(Argument); 38 static Type variableType = typeof(Variable); 39 static Type delegateArgumentType = typeof(DelegateArgument); 40 41 // MethodInfos cached for use in TryRewriteLambdaExpression 42 static MethodInfo activityContextGetValueGenericMethod = typeof(ActivityContext).GetMethod("GetValue", new Type[] { typeof(LocationReference) }); 43 static MethodInfo activityContextGetLocationGenericMethod = typeof(ActivityContext).GetMethod("GetLocation", new Type[] { typeof(LocationReference) }); 44 static MethodInfo locationReferenceGetLocationMethod = typeof(LocationReference).GetMethod("GetLocation", new Type[] { typeof(ActivityContext) }); 45 static MethodInfo argumentGetLocationMethod = typeof(Argument).GetMethod("GetLocation", new Type[] { typeof(ActivityContext) }); 46 static MethodInfo variableGetMethod = typeof(Variable).GetMethod("Get", new Type[] { typeof(ActivityContext) }); 47 static MethodInfo delegateArgumentGetMethod = typeof(DelegateArgument).GetMethod("Get", new Type[] { typeof(ActivityContext) }); 48 49 static MethodInfo PropertyDescriptorGetValue 50 { 51 get 52 { 53 if (propertyDescriptorGetValue == null) 54 { 55 propertyDescriptorGetValue = typeof(PropertyDescriptor).GetMethod("GetValue"); 56 } 57 58 return propertyDescriptorGetValue; 59 } 60 } 61 CreateIdentifierExpression(LocationReference locationReference)62 public static Expression CreateIdentifierExpression(LocationReference locationReference) 63 { 64 return Expression.Call(RuntimeContextParameter, activityContextGetValueGenericMethod.MakeGenericMethod(locationReference.Type), Expression.Constant(locationReference, typeof(LocationReference))); 65 } 66 67 // If we ever expand the depth to which we'll look through an expression for a location, 68 // then we also need to update the depth to which isLocationExpression is propagated in 69 // ExpressionUtilities.TryRewriteLambdaExpression and VisualBasicHelper.Rewrite. IsLocation(LambdaExpression expression, Type targetType, out string extraErrorMessage)70 public static bool IsLocation(LambdaExpression expression, Type targetType, out string extraErrorMessage) 71 { 72 extraErrorMessage = null; 73 Expression body = expression.Body; 74 75 if (targetType != null && body.Type != targetType) 76 { 77 // eg) LambdaReference<IComparable>((env) => strVar.Get(env)) 78 // you can have an expressionTree whose LambdaExpression.ReturnType == IComparable, 79 // while its LambdaExpression.Body.Type == String 80 // and not ever have Convert node in the tree. 81 extraErrorMessage = SR.MustMatchReferenceExpressionReturnType; 82 return false; 83 } 84 85 switch (body.NodeType) 86 { 87 case ExpressionType.ArrayIndex: 88 return true; 89 90 case ExpressionType.MemberAccess: 91 // This also handles variables, which are emitted as "context.GetLocation<T>("v").Value" 92 MemberExpression memberExpression = (MemberExpression)body; 93 MemberTypes memberType = memberExpression.Member.MemberType; 94 if (memberType == MemberTypes.Field) 95 { 96 FieldInfo fieldInfo = (FieldInfo)memberExpression.Member; 97 if (fieldInfo.IsInitOnly) 98 { 99 // readOnly field 100 return false; 101 } 102 return true; 103 } 104 else if (memberType == MemberTypes.Property) 105 { 106 PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member; 107 if (!propertyInfo.CanWrite) 108 { 109 // no Setter 110 return false; 111 } 112 return true; 113 } 114 break; 115 116 case ExpressionType.Call: 117 // Depends on the method being called. 118 // System.Array.Get --> multi-dimensional array 119 // get_Item --> might be an indexer property if it's special name & default etc. 120 121 MethodCallExpression callExpression = (MethodCallExpression)body; 122 MethodInfo method = callExpression.Method; 123 124 Type declaringType = method.DeclaringType; 125 if (declaringType.BaseType == TypeHelper.ArrayType && method.Name == "Get") 126 { 127 return true; 128 } 129 else if (method.IsSpecialName && method.Name.StartsWith("get_", StringComparison.Ordinal)) 130 { 131 return true; 132 } 133 else if (method.Name == "GetValue" && declaringType == activityContextType) 134 { 135 return true; 136 } 137 else if (method.Name == "Get" && declaringType.IsGenericType) 138 { 139 Type declaringTypeGenericDefinition = declaringType.GetGenericTypeDefinition(); 140 141 if (declaringTypeGenericDefinition == inOutArgumentGenericType || 142 declaringTypeGenericDefinition == outArgumentGenericType) 143 { 144 return true; 145 } 146 } 147 break; 148 149 case ExpressionType.Convert: 150 // a would-be-valid Location expression that is type converted is treated invalid 151 extraErrorMessage = SR.MustMatchReferenceExpressionReturnType; 152 return false; 153 } 154 return false; 155 } 156 CreateLocationFactory(LambdaExpression expression)157 public static LocationFactory<T> CreateLocationFactory<T>(LambdaExpression expression) 158 { 159 Expression body = expression.Body; 160 161 switch (body.NodeType) 162 { 163 case ExpressionType.ArrayIndex: 164 return new ArrayLocationFactory<T>(expression); 165 166 case ExpressionType.MemberAccess: 167 // This also handles variables, which are emitted as "context.GetLocation<T>("v").Value" 168 MemberTypes memberType = ((MemberExpression)body).Member.MemberType; 169 if (memberType == MemberTypes.Field) 170 { 171 return new FieldLocationFactory<T>(expression); 172 } 173 else if (memberType == MemberTypes.Property) 174 { 175 return new PropertyLocationFactory<T>(expression); 176 } 177 else 178 { 179 throw FxTrace.Exception.AsError(new NotSupportedException("Lvalues of member type " + memberType)); 180 } 181 182 case ExpressionType.Call: 183 // Depends on the method being called. 184 // System.Array.Get --> multi-dimensional array 185 // get_Item --> might be an indexer property if it's special name & default etc. 186 187 MethodCallExpression callExpression = (MethodCallExpression)body; 188 MethodInfo method = callExpression.Method; 189 190 Type declaringType = method.DeclaringType; 191 if (declaringType.BaseType == TypeHelper.ArrayType && method.Name == "Get") 192 { 193 return new MultidimensionalArrayLocationFactory<T>(expression); 194 } 195 else if (method.IsSpecialName && method.Name.StartsWith("get_", StringComparison.Ordinal)) 196 { 197 return new IndexerLocationFactory<T>(expression); 198 } 199 else if (method.Name == "GetValue" && declaringType == activityContextType) 200 { 201 return new LocationReferenceFactory<T>(callExpression.Arguments[0], expression.Parameters); 202 } 203 else if (method.Name == "Get" && declaringType.IsGenericType) 204 { 205 Type declaringTypeGenericDefinition = declaringType.GetGenericTypeDefinition(); 206 207 if (declaringTypeGenericDefinition == inOutArgumentGenericType || 208 declaringTypeGenericDefinition == outArgumentGenericType) 209 { 210 return new ArgumentFactory<T>(callExpression.Object, expression.Parameters); 211 } 212 } 213 214 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidExpressionForLocation(body.NodeType))); 215 216 default: 217 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidExpressionForLocation(body.NodeType))); 218 } 219 } 220 TryGetInlinedReference(CodeActivityPublicEnvironmentAccessor publicAccessor, LocationReference originalReference, bool isLocationExpression, out LocationReference inlinedReference)221 internal static bool TryGetInlinedReference(CodeActivityPublicEnvironmentAccessor publicAccessor, LocationReference originalReference, 222 bool isLocationExpression, out LocationReference inlinedReference) 223 { 224 if (isLocationExpression) 225 { 226 return publicAccessor.TryGetReferenceToPublicLocation(originalReference, true, out inlinedReference); 227 } 228 else 229 { 230 return publicAccessor.TryGetAccessToPublicLocation(originalReference, ArgumentDirection.In, true, out inlinedReference); 231 } 232 } 233 CreateParentReference(Expression expression, ReadOnlyCollection<ParameterExpression> lambdaParameters)234 static LocationFactory CreateParentReference(Expression expression, ReadOnlyCollection<ParameterExpression> lambdaParameters) 235 { 236 // create a LambdaExpression to get access to the expression 237 int parameterCount = lambdaParameters.Count; 238 Type genericFuncType = linqAssembly.GetType("System.Func`" + (parameterCount + 1), true); 239 Type[] delegateParameterTypes = new Type[parameterCount + 1]; 240 241 for (int i = 0; i < parameterCount; ++i) 242 { 243 delegateParameterTypes[i] = lambdaParameters[i].Type; 244 } 245 delegateParameterTypes[parameterCount] = expression.Type; 246 Type funcType = genericFuncType.MakeGenericType(delegateParameterTypes); 247 LambdaExpression parentLambda = Expression.Lambda(funcType, expression, lambdaParameters); 248 249 // call CreateLocationFactory<parentLambda.Type>(parentLambda); 250 MethodInfo typedMethod = createLocationFactoryGenericMethod.MakeGenericMethod(expression.Type); 251 return (LocationFactory)typedMethod.Invoke(null, new object[] { parentLambda }); 252 } 253 Compile(Expression objectExpression, ReadOnlyCollection<ParameterExpression> parametersCollection)254 static Func<ActivityContext, T> Compile<T>(Expression objectExpression, ReadOnlyCollection<ParameterExpression> parametersCollection) 255 { 256 ParameterExpression[] parameters = null; 257 if (parametersCollection != null) 258 { 259 parameters = parametersCollection.ToArray<ParameterExpression>(); 260 } 261 262 Expression<Func<ActivityContext, T>> objectLambda = Expression.Lambda<Func<ActivityContext, T>>(objectExpression, parameters); 263 return objectLambda.Compile(); 264 } 265 Evaluate(Expression objectExpression, ReadOnlyCollection<ParameterExpression> parametersCollection, ActivityContext context)266 static T Evaluate<T>(Expression objectExpression, ReadOnlyCollection<ParameterExpression> parametersCollection, ActivityContext context) 267 { 268 Func<ActivityContext, T> objectFunc = Compile<T>(objectExpression, parametersCollection); 269 return objectFunc(context); 270 } 271 272 // for single-dimensional arrays 273 class ArrayLocationFactory<T> : LocationFactory<T> 274 { 275 Func<ActivityContext, T[]> arrayFunction; 276 Func<ActivityContext, int> indexFunction; 277 ArrayLocationFactory(LambdaExpression expression)278 public ArrayLocationFactory(LambdaExpression expression) 279 { 280 Fx.Assert(expression.Body.NodeType == ExpressionType.ArrayIndex, "ArrayIndex expression required"); 281 BinaryExpression arrayIndexExpression = (BinaryExpression)expression.Body; 282 283 this.arrayFunction = ExpressionUtilities.Compile<T[]>(arrayIndexExpression.Left, expression.Parameters); 284 this.indexFunction = ExpressionUtilities.Compile<int>(arrayIndexExpression.Right, expression.Parameters); 285 } 286 CreateLocation(ActivityContext context)287 public override Location<T> CreateLocation(ActivityContext context) 288 { 289 return new ArrayLocation(this.arrayFunction(context), this.indexFunction(context)); 290 } 291 292 [DataContract] 293 internal class ArrayLocation : Location<T> 294 { 295 T[] array; 296 297 int index; 298 ArrayLocation(T[] array, int index)299 public ArrayLocation(T[] array, int index) 300 : base() 301 { 302 this.array = array; 303 this.index = index; 304 } 305 306 public override T Value 307 { 308 get 309 { 310 return this.array[this.index]; 311 } 312 set 313 { 314 this.array[this.index] = value; 315 } 316 } 317 318 [DataMember(Name = "array")] 319 internal T[] SerializedArray 320 { 321 get { return this.array; } 322 set { this.array = value; } 323 } 324 325 [DataMember(EmitDefaultValue = false, Name = "index")] 326 internal int SerializedIndex 327 { 328 get { return this.index; } 329 set { this.index = value; } 330 } 331 } 332 } 333 334 class FieldLocationFactory<T> : LocationFactory<T> 335 { 336 FieldInfo fieldInfo; 337 Func<ActivityContext, object> ownerFunction; 338 LocationFactory parentFactory; 339 FieldLocationFactory(LambdaExpression expression)340 public FieldLocationFactory(LambdaExpression expression) 341 { 342 Fx.Assert(expression.Body.NodeType == ExpressionType.MemberAccess, "field expression required"); 343 MemberExpression memberExpression = (MemberExpression)expression.Body; 344 345 Fx.Assert(memberExpression.Member.MemberType == MemberTypes.Field, "member field expected"); 346 this.fieldInfo = (FieldInfo)memberExpression.Member; 347 348 if (this.fieldInfo.IsStatic) 349 { 350 this.ownerFunction = null; 351 } 352 else 353 { 354 this.ownerFunction = ExpressionUtilities.Compile<object>( 355 Expression.Convert(memberExpression.Expression, TypeHelper.ObjectType), expression.Parameters); 356 } 357 358 if (this.fieldInfo.DeclaringType.IsValueType) 359 { 360 // may want to set a struct, so we need to make an expression in order to set the parent 361 parentFactory = CreateParentReference(memberExpression.Expression, expression.Parameters); 362 } 363 } 364 CreateLocation(ActivityContext context)365 public override Location<T> CreateLocation(ActivityContext context) 366 { 367 object owner = null; 368 if (this.ownerFunction != null) 369 { 370 owner = this.ownerFunction(context); 371 } 372 373 Location parent = null; 374 if (parentFactory != null) 375 { 376 parent = parentFactory.CreateLocation(context); 377 } 378 return new FieldLocation(this.fieldInfo, owner, parent); 379 } 380 381 [DataContract] 382 internal class FieldLocation : Location<T> 383 { 384 FieldInfo fieldInfo; 385 386 object owner; 387 388 Location parent; 389 FieldLocation(FieldInfo fieldInfo, object owner, Location parent)390 public FieldLocation(FieldInfo fieldInfo, object owner, Location parent) 391 : base() 392 { 393 this.fieldInfo = fieldInfo; 394 this.owner = owner; 395 this.parent = parent; 396 } 397 398 [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes, 399 Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")] 400 public override T Value 401 { 402 get 403 { 404 if (this.owner == null && !this.fieldInfo.IsStatic) 405 { 406 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.fieldInfo.Name))); 407 } 408 409 return (T)this.fieldInfo.GetValue(this.owner); 410 } 411 set 412 { 413 if (this.owner == null && !this.fieldInfo.IsStatic) 414 { 415 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.fieldInfo.Name))); 416 } 417 418 this.fieldInfo.SetValue(this.owner, value); 419 if (this.parent != null) 420 { 421 // Looks like we are trying to set a field on a struct 422 // Calling SetValue simply sets the field on the local copy of the struct, which is not very helpful 423 // Since we have a copy, assign it back to the parent 424 this.parent.Value = this.owner; 425 } 426 } 427 } 428 429 [DataMember(Name = "fieldInfo")] 430 internal FieldInfo SerializedFieldInfo 431 { 432 get { return this.fieldInfo; } 433 set { this.fieldInfo = value; } 434 } 435 436 [DataMember(EmitDefaultValue = false, Name = "owner")] 437 internal object SerializedOwner 438 { 439 get { return this.owner; } 440 set { this.owner = value; } 441 } 442 443 [DataMember(EmitDefaultValue = false, Name = "parent")] 444 internal Location SerializedParent 445 { 446 get { return this.parent; } 447 set { this.parent = value; } 448 } 449 } 450 } 451 452 class ArgumentFactory<T> : LocationFactory<T> 453 { 454 Func<ActivityContext, Argument> argumentFunction; 455 ArgumentFactory(Expression argumentExpression, ReadOnlyCollection<ParameterExpression> expressionParameters)456 public ArgumentFactory(Expression argumentExpression, ReadOnlyCollection<ParameterExpression> expressionParameters) 457 { 458 this.argumentFunction = ExpressionUtilities.Compile<Argument>(argumentExpression, expressionParameters); 459 } 460 CreateLocation(ActivityContext context)461 public override Location<T> CreateLocation(ActivityContext context) 462 { 463 Argument argument = this.argumentFunction(context); 464 465 return argument.RuntimeArgument.GetLocation(context) as Location<T>; 466 } 467 } 468 469 class LocationReferenceFactory<T> : LocationFactory<T> 470 { 471 Func<ActivityContext, LocationReference> locationReferenceFunction; 472 LocationReferenceFactory(Expression locationReferenceExpression, ReadOnlyCollection<ParameterExpression> expressionParameters)473 public LocationReferenceFactory(Expression locationReferenceExpression, ReadOnlyCollection<ParameterExpression> expressionParameters) 474 { 475 this.locationReferenceFunction = ExpressionUtilities.Compile<LocationReference>(locationReferenceExpression, expressionParameters); 476 } 477 CreateLocation(ActivityContext context)478 public override Location<T> CreateLocation(ActivityContext context) 479 { 480 LocationReference locationReference = this.locationReferenceFunction(context); 481 return locationReference.GetLocation(context) as Location<T>; 482 } 483 } 484 485 class IndexerLocationFactory<T> : LocationFactory<T> 486 { 487 MethodInfo getItemMethod; 488 string indexerName; 489 MethodInfo setItemMethod; 490 Func<ActivityContext, object>[] setItemArgumentFunctions; 491 Func<ActivityContext, object> targetObjectFunction; 492 IndexerLocationFactory(LambdaExpression expression)493 public IndexerLocationFactory(LambdaExpression expression) 494 { 495 Fx.Assert(expression.Body.NodeType == ExpressionType.Call, "Call expression required."); 496 497 MethodCallExpression callExpression = (MethodCallExpression)expression.Body; 498 this.getItemMethod = callExpression.Method; 499 500 Fx.Assert(this.getItemMethod.IsSpecialName && this.getItemMethod.Name.StartsWith("get_", StringComparison.Ordinal), "Special get_Item method required."); 501 502 // Get the set_Item accessor for the same set of parameter/return types if any. 503 this.indexerName = this.getItemMethod.Name.Substring(4); 504 string setItemName = "set_" + this.indexerName; 505 ParameterInfo[] getItemParameters = this.getItemMethod.GetParameters(); 506 Type[] setItemParameterTypes = new Type[getItemParameters.Length + 1]; 507 508 for (int i = 0; i < getItemParameters.Length; i++) 509 { 510 setItemParameterTypes[i] = getItemParameters[i].ParameterType; 511 } 512 setItemParameterTypes[getItemParameters.Length] = this.getItemMethod.ReturnType; 513 514 this.setItemMethod = this.getItemMethod.DeclaringType.GetMethod( 515 setItemName, BindingFlags.Public | BindingFlags.Instance, null, setItemParameterTypes, null); 516 517 if (this.setItemMethod != null) 518 { 519 // Get the target object and all the setter's arguments 520 // (minus the actual value to be set). 521 this.targetObjectFunction = ExpressionUtilities.Compile<object>(callExpression.Object, expression.Parameters); 522 523 this.setItemArgumentFunctions = new Func<ActivityContext, object>[callExpression.Arguments.Count]; 524 for (int i = 0; i < callExpression.Arguments.Count; i++) 525 { 526 // convert value types to objects since Linq doesn't do it automatically 527 Expression argument = callExpression.Arguments[i]; 528 if (argument.Type.IsValueType) 529 { 530 argument = Expression.Convert(argument, TypeHelper.ObjectType); 531 } 532 this.setItemArgumentFunctions[i] = ExpressionUtilities.Compile<object>(argument, expression.Parameters); 533 } 534 } 535 } 536 CreateLocation(ActivityContext context)537 public override Location<T> CreateLocation(ActivityContext context) 538 { 539 object targetObject = null; 540 object[] setItemArguments = null; 541 542 if (this.setItemMethod != null) 543 { 544 targetObject = this.targetObjectFunction(context); 545 546 setItemArguments = new object[this.setItemArgumentFunctions.Length]; 547 548 for (int i = 0; i < this.setItemArgumentFunctions.Length; i++) 549 { 550 setItemArguments[i] = this.setItemArgumentFunctions[i](context); 551 } 552 } 553 554 return new IndexerLocation(this.indexerName, this.getItemMethod, this.setItemMethod, targetObject, setItemArguments); 555 } 556 557 [DataContract] 558 internal class IndexerLocation : Location<T> 559 { 560 string indexerName; 561 562 MethodInfo getItemMethod; 563 564 MethodInfo setItemMethod; 565 566 object targetObject; 567 568 object[] setItemArguments; 569 IndexerLocation(string indexerName, MethodInfo getItemMethod, MethodInfo setItemMethod, object targetObject, object[] getItemArguments)570 public IndexerLocation(string indexerName, MethodInfo getItemMethod, MethodInfo setItemMethod, 571 object targetObject, object[] getItemArguments) 572 : base() 573 { 574 this.indexerName = indexerName; 575 this.getItemMethod = getItemMethod; 576 this.setItemMethod = setItemMethod; 577 this.targetObject = targetObject; 578 this.setItemArguments = getItemArguments; 579 } 580 581 [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes, 582 Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")] 583 public override T Value 584 { 585 get 586 { 587 if (this.targetObject == null && !this.getItemMethod.IsStatic) 588 { 589 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.getItemMethod.Name))); 590 } 591 592 return (T)this.getItemMethod.Invoke(this.targetObject, this.setItemArguments); 593 } 594 595 set 596 { 597 598 if (this.setItemMethod == null) 599 { 600 string targetObjectTypeName = this.targetObject.GetType().Name; 601 throw FxTrace.Exception.AsError(new InvalidOperationException( 602 SR.MissingSetAccessorForIndexer(this.indexerName, targetObjectTypeName))); 603 } 604 605 if (this.targetObject == null && !this.setItemMethod.IsStatic) 606 { 607 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.setItemMethod.Name))); 608 } 609 610 object[] localSetItemArguments = new object[this.setItemArguments.Length + 1]; 611 Array.ConstrainedCopy(this.setItemArguments, 0, localSetItemArguments, 0, this.setItemArguments.Length); 612 localSetItemArguments[localSetItemArguments.Length - 1] = value; 613 614 this.setItemMethod.Invoke(this.targetObject, localSetItemArguments); 615 } 616 } 617 618 [DataMember(Name = "indexerName")] 619 internal string SerializedIndexerName 620 { 621 get { return this.indexerName; } 622 set { this.indexerName = value; } 623 } 624 625 [DataMember(EmitDefaultValue = false, Name = "getItemMethod")] 626 internal MethodInfo SerializedGetItemMethod 627 { 628 get { return this.getItemMethod; } 629 set { this.getItemMethod = value; } 630 } 631 632 [DataMember(EmitDefaultValue = false, Name = "setItemMethod")] 633 internal MethodInfo SerializedSetItemMethod 634 { 635 get { return this.setItemMethod; } 636 set { this.setItemMethod = value; } 637 } 638 639 [DataMember(EmitDefaultValue = false, Name = "targetObject")] 640 internal object SerializedTargetObject 641 { 642 get { return this.targetObject; } 643 set { this.targetObject = value; } 644 } 645 646 [DataMember(EmitDefaultValue = false, Name = "setItemArguments")] 647 internal object[] SerializedSetItemArguments 648 { 649 get { return this.setItemArguments; } 650 set { this.setItemArguments = value; } 651 } 652 } 653 } 654 655 class MultidimensionalArrayLocationFactory<T> : LocationFactory<T> 656 { 657 Func<ActivityContext, Array> arrayFunction; 658 Func<ActivityContext, int>[] indexFunctions; 659 MultidimensionalArrayLocationFactory(LambdaExpression expression)660 public MultidimensionalArrayLocationFactory(LambdaExpression expression) 661 { 662 Fx.Assert(expression.Body.NodeType == ExpressionType.Call, "Call expression required."); 663 MethodCallExpression callExpression = (MethodCallExpression)expression.Body; 664 665 this.arrayFunction = ExpressionUtilities.Compile<Array>( 666 callExpression.Object, expression.Parameters); 667 668 this.indexFunctions = new Func<ActivityContext, int>[callExpression.Arguments.Count]; 669 for (int i = 0; i < this.indexFunctions.Length; i++) 670 { 671 this.indexFunctions[i] = ExpressionUtilities.Compile<int>( 672 callExpression.Arguments[i], expression.Parameters); 673 } 674 } 675 CreateLocation(ActivityContext context)676 public override Location<T> CreateLocation(ActivityContext context) 677 { 678 int[] indices = new int[this.indexFunctions.Length]; 679 for (int i = 0; i < indices.Length; i++) 680 { 681 indices[i] = this.indexFunctions[i](context); 682 } 683 return new MultidimensionalArrayLocation(this.arrayFunction(context), indices); 684 } 685 686 [DataContract] 687 internal class MultidimensionalArrayLocation : Location<T> 688 { 689 Array array; 690 691 int[] indices; 692 MultidimensionalArrayLocation(Array array, int[] indices)693 public MultidimensionalArrayLocation(Array array, int[] indices) 694 : base() 695 { 696 this.array = array; 697 this.indices = indices; 698 } 699 700 public override T Value 701 { 702 get 703 { 704 return (T)this.array.GetValue(this.indices); 705 } 706 707 set 708 { 709 this.array.SetValue(value, this.indices); 710 } 711 } 712 713 [DataMember(Name = "array")] 714 internal Array SerializedArray 715 { 716 get { return this.array; } 717 set { this.array = value; } 718 } 719 720 [DataMember(Name = "indices")] 721 internal int[] SerializedIndicess 722 { 723 get { return this.indices; } 724 set { this.indices = value; } 725 } 726 } 727 } 728 729 class PropertyLocationFactory<T> : LocationFactory<T> 730 { 731 Func<ActivityContext, object> ownerFunction; 732 PropertyInfo propertyInfo; 733 LocationFactory parentFactory; 734 PropertyLocationFactory(LambdaExpression expression)735 public PropertyLocationFactory(LambdaExpression expression) 736 { 737 Fx.Assert(expression.Body.NodeType == ExpressionType.MemberAccess, "member access expression required"); 738 MemberExpression memberExpression = (MemberExpression)expression.Body; 739 740 Fx.Assert(memberExpression.Member.MemberType == MemberTypes.Property, "property access expression expected"); 741 this.propertyInfo = (PropertyInfo)memberExpression.Member; 742 743 if (memberExpression.Expression == null) 744 { 745 // static property 746 this.ownerFunction = null; 747 } 748 else 749 { 750 this.ownerFunction = ExpressionUtilities.Compile<object>( 751 Expression.Convert(memberExpression.Expression, TypeHelper.ObjectType), expression.Parameters); 752 } 753 754 if (this.propertyInfo.DeclaringType.IsValueType) 755 { 756 // may want to set a struct, so we need to make an expression in order to set the parent 757 parentFactory = CreateParentReference(memberExpression.Expression, expression.Parameters); 758 } 759 } 760 CreateLocation(ActivityContext context)761 public override Location<T> CreateLocation(ActivityContext context) 762 { 763 object owner = null; 764 if (this.ownerFunction != null) 765 { 766 owner = this.ownerFunction(context); 767 } 768 769 Location parent = null; 770 if (parentFactory != null) 771 { 772 parent = parentFactory.CreateLocation(context); 773 } 774 return new PropertyLocation(this.propertyInfo, owner, parent); 775 } 776 777 [DataContract] 778 internal class PropertyLocation : Location<T> 779 { 780 object owner; 781 782 PropertyInfo propertyInfo; 783 784 Location parent; 785 PropertyLocation(PropertyInfo propertyInfo, object owner, Location parent)786 public PropertyLocation(PropertyInfo propertyInfo, object owner, Location parent) 787 : base() 788 { 789 this.propertyInfo = propertyInfo; 790 this.owner = owner; 791 this.parent = parent; 792 } 793 794 [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes, 795 Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")] 796 public override T Value 797 { 798 get 799 { 800 // Only allow access to public properties, EXCEPT that Locations are top-level variables 801 // from the other's perspective, not internal properties, so they're okay as a special case. 802 // E.g. "[N]" from the user's perspective is not accessing a nonpublic property, even though 803 // at an implementation level it is. 804 MethodInfo getMethodInfo = this.propertyInfo.GetGetMethod(); 805 if (getMethodInfo == null && !TypeHelper.AreTypesCompatible(this.propertyInfo.DeclaringType, typeof(Location))) 806 { 807 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WriteonlyPropertyCannotBeRead(this.propertyInfo.DeclaringType, this.propertyInfo.Name))); 808 } 809 810 if (this.owner == null && (getMethodInfo == null || !getMethodInfo.IsStatic)) 811 { 812 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.propertyInfo.Name))); 813 } 814 815 // Okay, it's public 816 return (T)this.propertyInfo.GetValue(this.owner, null); 817 } 818 819 set 820 { 821 // Only allow access to public properties, EXCEPT that Locations are top-level variables 822 // from the other's perspective, not internal properties, so they're okay as a special case. 823 // E.g. "[N]" from the user's perspective is not accessing a nonpublic property, even though 824 // at an implementation level it is. 825 MethodInfo setMethodInfo = this.propertyInfo.GetSetMethod(); 826 if (setMethodInfo == null && !TypeHelper.AreTypesCompatible(this.propertyInfo.DeclaringType, typeof(Location))) 827 { 828 throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ReadonlyPropertyCannotBeSet(this.propertyInfo.DeclaringType, this.propertyInfo.Name))); 829 } 830 831 if (this.owner == null && (setMethodInfo == null || !setMethodInfo.IsStatic)) 832 { 833 throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.propertyInfo.Name))); 834 } 835 836 // Okay, it's public 837 this.propertyInfo.SetValue(this.owner, value, null); 838 if (this.parent != null) 839 { 840 // Looks like we are trying to set a property on a struct 841 // Calling SetValue simply sets the property on the local copy of the struct, which is not very helpful 842 // Since we have a copy, assign it back to the parent 843 this.parent.Value = this.owner; 844 } 845 } 846 } 847 848 [DataMember(EmitDefaultValue = false, Name = "owner")] 849 internal object SerializedOwner 850 { 851 get { return this.owner; } 852 set { this.owner = value; } 853 } 854 855 [DataMember(Name = "propertyInfo")] 856 internal PropertyInfo SerializedPropertyInfo 857 { 858 get { return this.propertyInfo; } 859 set { this.propertyInfo = value; } 860 } 861 862 [DataMember(EmitDefaultValue = false, Name = "parent")] 863 internal Location SerializedParent 864 { 865 get { return this.parent; } 866 set { this.parent = value; } 867 } 868 } 869 } 870 871 // Returns true if it changed the expression (newExpression != expression). 872 // If it returns false then newExpression is set equal to expression. 873 // This method uses the publicAccessor parameter to generate violations (workflow 874 // artifacts which are not visible) and to generate inline references 875 // (references at a higher scope which can be resolved at runtime). TryRewriteLambdaExpression(Expression expression, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression = false)876 public static bool TryRewriteLambdaExpression(Expression expression, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression = false) 877 { 878 newExpression = expression; 879 880 if (expression == null) 881 { 882 return false; 883 } 884 885 // Share some local declarations across the switch 886 Expression left = null; 887 Expression right = null; 888 Expression other = null; 889 bool hasChanged = false; 890 IList<Expression> expressionList = null; 891 IList<ElementInit> initializerList = null; 892 IList<MemberBinding> bindingList = null; 893 MethodCallExpression methodCall = null; 894 BinaryExpression binaryExpression = null; 895 NewArrayExpression newArray = null; 896 UnaryExpression unaryExpression = null; 897 898 switch (expression.NodeType) 899 { 900 case ExpressionType.Add: 901 case ExpressionType.AddChecked: 902 case ExpressionType.And: 903 case ExpressionType.AndAlso: 904 case ExpressionType.Coalesce: 905 case ExpressionType.Divide: 906 case ExpressionType.Equal: 907 case ExpressionType.ExclusiveOr: 908 case ExpressionType.GreaterThan: 909 case ExpressionType.GreaterThanOrEqual: 910 case ExpressionType.LeftShift: 911 case ExpressionType.LessThan: 912 case ExpressionType.LessThanOrEqual: 913 case ExpressionType.Modulo: 914 case ExpressionType.Multiply: 915 case ExpressionType.MultiplyChecked: 916 case ExpressionType.NotEqual: 917 case ExpressionType.Or: 918 case ExpressionType.OrElse: 919 case ExpressionType.Power: 920 case ExpressionType.RightShift: 921 case ExpressionType.Subtract: 922 case ExpressionType.SubtractChecked: 923 binaryExpression = (BinaryExpression)expression; 924 925 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, publicAccessor); 926 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, publicAccessor); 927 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Conversion, out other, publicAccessor); 928 929 if (hasChanged) 930 { 931 newExpression = Expression.MakeBinary( 932 binaryExpression.NodeType, 933 left, 934 right, 935 binaryExpression.IsLiftedToNull, 936 binaryExpression.Method, 937 (LambdaExpression)other); 938 } 939 break; 940 941 case ExpressionType.Conditional: 942 ConditionalExpression conditional = (ConditionalExpression)expression; 943 944 hasChanged |= TryRewriteLambdaExpression(conditional.Test, out other, publicAccessor); 945 hasChanged |= TryRewriteLambdaExpression(conditional.IfTrue, out left, publicAccessor); 946 hasChanged |= TryRewriteLambdaExpression(conditional.IfFalse, out right, publicAccessor); 947 948 if (hasChanged) 949 { 950 newExpression = Expression.Condition( 951 other, 952 left, 953 right); 954 } 955 break; 956 957 case ExpressionType.Constant: 958 break; 959 960 case ExpressionType.Invoke: 961 InvocationExpression invocation = (InvocationExpression)expression; 962 963 hasChanged |= TryRewriteLambdaExpression(invocation.Expression, out other, publicAccessor); 964 hasChanged |= TryRewriteLambdaExpressionCollection(invocation.Arguments, out expressionList, publicAccessor); 965 966 if (hasChanged) 967 { 968 newExpression = Expression.Invoke( 969 other, 970 expressionList); 971 } 972 break; 973 974 case ExpressionType.Lambda: 975 LambdaExpression lambda = (LambdaExpression)expression; 976 977 hasChanged |= TryRewriteLambdaExpression(lambda.Body, out other, publicAccessor, isLocationExpression); 978 979 if (hasChanged) 980 { 981 newExpression = Expression.Lambda( 982 lambda.Type, 983 other, 984 lambda.Parameters); 985 } 986 break; 987 988 case ExpressionType.ListInit: 989 ListInitExpression listInit = (ListInitExpression)expression; 990 991 hasChanged |= TryRewriteLambdaExpression(listInit.NewExpression, out other, publicAccessor); 992 hasChanged |= TryRewriteLambdaExpressionInitializersCollection(listInit.Initializers, out initializerList, publicAccessor); 993 994 if (hasChanged) 995 { 996 newExpression = Expression.ListInit( 997 (NewExpression)other, 998 initializerList); 999 } 1000 break; 1001 1002 case ExpressionType.Parameter: 1003 break; 1004 1005 case ExpressionType.MemberAccess: 1006 MemberExpression memberExpression = (MemberExpression)expression; 1007 1008 // When creating a location for a member on a struct, we also need a location 1009 // for the struct (so we don't just set the member on a copy of the struct) 1010 bool subTreeIsLocationExpression = isLocationExpression && memberExpression.Member.DeclaringType.IsValueType; 1011 1012 hasChanged |= TryRewriteLambdaExpression(memberExpression.Expression, out other, publicAccessor, subTreeIsLocationExpression); 1013 1014 if (hasChanged) 1015 { 1016 newExpression = Expression.MakeMemberAccess( 1017 other, 1018 memberExpression.Member); 1019 } 1020 break; 1021 1022 case ExpressionType.MemberInit: 1023 MemberInitExpression memberInit = (MemberInitExpression)expression; 1024 1025 hasChanged |= TryRewriteLambdaExpression(memberInit.NewExpression, out other, publicAccessor); 1026 hasChanged |= TryRewriteLambdaExpressionBindingsCollection(memberInit.Bindings, out bindingList, publicAccessor); 1027 1028 if (hasChanged) 1029 { 1030 newExpression = Expression.MemberInit( 1031 (NewExpression)other, 1032 bindingList); 1033 } 1034 break; 1035 1036 case ExpressionType.ArrayIndex: 1037 // ArrayIndex can be a MethodCallExpression or a BinaryExpression 1038 methodCall = expression as MethodCallExpression; 1039 if (methodCall != null) 1040 { 1041 hasChanged |= TryRewriteLambdaExpression(methodCall.Object, out other, publicAccessor); 1042 hasChanged |= TryRewriteLambdaExpressionCollection(methodCall.Arguments, out expressionList, publicAccessor); 1043 1044 if (hasChanged) 1045 { 1046 newExpression = Expression.ArrayIndex( 1047 other, 1048 expressionList); 1049 } 1050 } 1051 else 1052 { 1053 binaryExpression = (BinaryExpression)expression; 1054 1055 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, publicAccessor); 1056 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, publicAccessor); 1057 1058 if (hasChanged) 1059 { 1060 newExpression = Expression.ArrayIndex( 1061 left, 1062 right); 1063 } 1064 } 1065 break; 1066 1067 case ExpressionType.Call: 1068 methodCall = (MethodCallExpression)expression; 1069 1070 // TryRewriteMethodCall does all the real work 1071 hasChanged = TryRewriteMethodCall(methodCall, out newExpression, publicAccessor, isLocationExpression); 1072 break; 1073 1074 case ExpressionType.NewArrayInit: 1075 newArray = (NewArrayExpression)expression; 1076 1077 hasChanged |= TryRewriteLambdaExpressionCollection(newArray.Expressions, out expressionList, publicAccessor); 1078 1079 if (hasChanged) 1080 { 1081 newExpression = Expression.NewArrayInit( 1082 newArray.Type.GetElementType(), 1083 expressionList); 1084 } 1085 break; 1086 1087 case ExpressionType.NewArrayBounds: 1088 newArray = (NewArrayExpression)expression; 1089 1090 hasChanged |= TryRewriteLambdaExpressionCollection(newArray.Expressions, out expressionList, publicAccessor); 1091 1092 if (hasChanged) 1093 { 1094 newExpression = Expression.NewArrayBounds( 1095 newArray.Type.GetElementType(), 1096 expressionList); 1097 } 1098 break; 1099 1100 case ExpressionType.New: 1101 NewExpression objectCreationExpression = (NewExpression)expression; 1102 1103 if (objectCreationExpression.Constructor == null) 1104 { 1105 // must be creating a valuetype 1106 Fx.Assert(objectCreationExpression.Arguments.Count == 0, "NewExpression with null Constructor but some arguments"); 1107 } 1108 else 1109 { 1110 hasChanged |= TryRewriteLambdaExpressionCollection(objectCreationExpression.Arguments, out expressionList, publicAccessor); 1111 1112 if (hasChanged) 1113 { 1114 newExpression = objectCreationExpression.Update(expressionList); 1115 } 1116 } 1117 break; 1118 1119 case ExpressionType.TypeIs: 1120 TypeBinaryExpression typeBinary = (TypeBinaryExpression)expression; 1121 1122 hasChanged |= TryRewriteLambdaExpression(typeBinary.Expression, out other, publicAccessor); 1123 1124 if (hasChanged) 1125 { 1126 newExpression = Expression.TypeIs( 1127 other, 1128 typeBinary.TypeOperand); 1129 } 1130 break; 1131 1132 case ExpressionType.ArrayLength: 1133 case ExpressionType.Convert: 1134 case ExpressionType.ConvertChecked: 1135 case ExpressionType.Negate: 1136 case ExpressionType.NegateChecked: 1137 case ExpressionType.Not: 1138 case ExpressionType.Quote: 1139 case ExpressionType.TypeAs: 1140 unaryExpression = (UnaryExpression)expression; 1141 1142 hasChanged |= TryRewriteLambdaExpression(unaryExpression.Operand, out left, publicAccessor); 1143 1144 if (hasChanged) 1145 { 1146 newExpression = Expression.MakeUnary( 1147 unaryExpression.NodeType, 1148 left, 1149 unaryExpression.Type, 1150 unaryExpression.Method); 1151 } 1152 break; 1153 1154 case ExpressionType.UnaryPlus: 1155 unaryExpression = (UnaryExpression)expression; 1156 1157 hasChanged |= TryRewriteLambdaExpression(unaryExpression.Operand, out left, publicAccessor); 1158 1159 if (hasChanged) 1160 { 1161 newExpression = Expression.UnaryPlus( 1162 left, 1163 unaryExpression.Method); 1164 } 1165 break; 1166 1167 // Expression Tree V2.0 types. This is due to the hosted VB compiler generating ET V2.0 nodes. 1168 1169 case ExpressionType.Block: 1170 BlockExpression block = (BlockExpression)expression; 1171 1172 hasChanged |= TryRewriteLambdaExpressionCollection(block.Expressions, out expressionList, publicAccessor); 1173 1174 if (hasChanged) 1175 { 1176 // Parameter collections are never rewritten 1177 newExpression = Expression.Block(block.Variables, expressionList); 1178 } 1179 break; 1180 1181 case ExpressionType.Assign: 1182 binaryExpression = (BinaryExpression)expression; 1183 1184 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, publicAccessor); 1185 hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, publicAccessor); 1186 1187 if (hasChanged) 1188 { 1189 newExpression = Expression.Assign(left, right); 1190 } 1191 break; 1192 } 1193 1194 return hasChanged; 1195 } 1196 TryRewriteLambdaExpressionBindingsCollection(IList<MemberBinding> bindings, out IList<MemberBinding> newBindings, CodeActivityPublicEnvironmentAccessor publicAccessor)1197 static bool TryRewriteLambdaExpressionBindingsCollection(IList<MemberBinding> bindings, out IList<MemberBinding> newBindings, CodeActivityPublicEnvironmentAccessor publicAccessor) 1198 { 1199 IList<MemberBinding> temporaryBindings = null; 1200 1201 for (int i = 0; i < bindings.Count; i++) 1202 { 1203 MemberBinding binding = bindings[i]; 1204 1205 MemberBinding newBinding; 1206 if (TryRewriteMemberBinding(binding, out newBinding, publicAccessor)) 1207 { 1208 if (temporaryBindings == null) 1209 { 1210 // We initialize this list with the unchanged bindings 1211 temporaryBindings = new List<MemberBinding>(bindings.Count); 1212 1213 for (int j = 0; j < i; j++) 1214 { 1215 temporaryBindings.Add(bindings[j]); 1216 } 1217 } 1218 } 1219 1220 // At this point newBinding is either the updated binding (if 1221 // rewrite returned true) or the original binding (if false 1222 // was returned) 1223 if (temporaryBindings != null) 1224 { 1225 temporaryBindings.Add(newBinding); 1226 } 1227 } 1228 1229 if (temporaryBindings != null) 1230 { 1231 newBindings = temporaryBindings; 1232 return true; 1233 } 1234 else 1235 { 1236 newBindings = bindings; 1237 return false; 1238 } 1239 } 1240 TryRewriteMemberBinding(MemberBinding binding, out MemberBinding newBinding, CodeActivityPublicEnvironmentAccessor publicAccessor)1241 static bool TryRewriteMemberBinding(MemberBinding binding, out MemberBinding newBinding, CodeActivityPublicEnvironmentAccessor publicAccessor) 1242 { 1243 newBinding = binding; 1244 1245 bool hasChanged = false; 1246 Expression other = null; 1247 IList<ElementInit> initializerList = null; 1248 IList<MemberBinding> bindingList = null; 1249 1250 switch (binding.BindingType) 1251 { 1252 case MemberBindingType.Assignment: 1253 MemberAssignment assignment = (MemberAssignment)binding; 1254 1255 hasChanged |= TryRewriteLambdaExpression(assignment.Expression, out other, publicAccessor); 1256 1257 if (hasChanged) 1258 { 1259 newBinding = Expression.Bind(assignment.Member, other); 1260 } 1261 break; 1262 1263 case MemberBindingType.ListBinding: 1264 MemberListBinding list = (MemberListBinding)binding; 1265 1266 hasChanged |= TryRewriteLambdaExpressionInitializersCollection(list.Initializers, out initializerList, publicAccessor); 1267 1268 if (hasChanged) 1269 { 1270 newBinding = Expression.ListBind(list.Member, initializerList); 1271 } 1272 break; 1273 1274 case MemberBindingType.MemberBinding: 1275 MemberMemberBinding member = (MemberMemberBinding)binding; 1276 1277 hasChanged |= TryRewriteLambdaExpressionBindingsCollection(member.Bindings, out bindingList, publicAccessor); 1278 1279 if (hasChanged) 1280 { 1281 newBinding = Expression.MemberBind(member.Member, bindingList); 1282 } 1283 break; 1284 } 1285 1286 return hasChanged; 1287 } 1288 1289 TryRewriteLambdaExpressionCollection(IList<Expression> expressions, out IList<Expression> newExpressions, CodeActivityPublicEnvironmentAccessor publicAccessor)1290 static bool TryRewriteLambdaExpressionCollection(IList<Expression> expressions, out IList<Expression> newExpressions, CodeActivityPublicEnvironmentAccessor publicAccessor) 1291 { 1292 IList<Expression> temporaryExpressions = null; 1293 1294 for (int i = 0; i < expressions.Count; i++) 1295 { 1296 Expression expression = expressions[i]; 1297 1298 Expression newExpression; 1299 if (TryRewriteLambdaExpression(expression, out newExpression, publicAccessor)) 1300 { 1301 if (temporaryExpressions == null) 1302 { 1303 // We initialize the list by copying all of the unchanged 1304 // expressions over 1305 temporaryExpressions = new List<Expression>(expressions.Count); 1306 1307 for (int j = 0; j < i; j++) 1308 { 1309 temporaryExpressions.Add(expressions[j]); 1310 } 1311 } 1312 } 1313 1314 // newExpression will either be set to the new expression (true was 1315 // returned) or the original expression (false was returned) 1316 if (temporaryExpressions != null) 1317 { 1318 temporaryExpressions.Add(newExpression); 1319 } 1320 } 1321 1322 if (temporaryExpressions != null) 1323 { 1324 newExpressions = temporaryExpressions; 1325 return true; 1326 } 1327 else 1328 { 1329 newExpressions = expressions; 1330 return false; 1331 } 1332 } 1333 TryRewriteLambdaExpressionInitializersCollection(IList<ElementInit> initializers, out IList<ElementInit> newInitializers, CodeActivityPublicEnvironmentAccessor publicAccessor)1334 static bool TryRewriteLambdaExpressionInitializersCollection(IList<ElementInit> initializers, out IList<ElementInit> newInitializers, CodeActivityPublicEnvironmentAccessor publicAccessor) 1335 { 1336 IList<ElementInit> temporaryInitializers = null; 1337 1338 for (int i = 0; i < initializers.Count; i++) 1339 { 1340 ElementInit elementInit = initializers[i]; 1341 1342 IList<Expression> newExpressions; 1343 if (TryRewriteLambdaExpressionCollection(elementInit.Arguments, out newExpressions, publicAccessor)) 1344 { 1345 if (temporaryInitializers == null) 1346 { 1347 // We initialize the list by copying all of the unchanged 1348 // initializers over 1349 temporaryInitializers = new List<ElementInit>(initializers.Count); 1350 1351 for (int j = 0; j < i; j++) 1352 { 1353 temporaryInitializers.Add(initializers[j]); 1354 } 1355 } 1356 1357 elementInit = Expression.ElementInit(elementInit.AddMethod, newExpressions); 1358 } 1359 1360 if (temporaryInitializers != null) 1361 { 1362 temporaryInitializers.Add(elementInit); 1363 } 1364 } 1365 1366 if (temporaryInitializers != null) 1367 { 1368 newInitializers = temporaryInitializers; 1369 return true; 1370 } 1371 else 1372 { 1373 newInitializers = initializers; 1374 return false; 1375 } 1376 } 1377 TryGetInlinedArgumentReference(MethodCallExpression originalExpression, Expression argumentExpression, out LocationReference inlinedReference, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1378 static bool TryGetInlinedArgumentReference(MethodCallExpression originalExpression, Expression argumentExpression, out LocationReference inlinedReference, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1379 { 1380 inlinedReference = null; 1381 1382 Argument argument = null; 1383 object tempArgument; 1384 1385 if (CustomMemberResolver(argumentExpression, out tempArgument) && tempArgument is Argument) 1386 { 1387 argument = (Argument)tempArgument; 1388 } 1389 else 1390 { 1391 try 1392 { 1393 Expression<Func<Argument>> argumentLambda = Expression.Lambda<Func<Argument>>(argumentExpression); 1394 Func<Argument> argumentFunc = argumentLambda.Compile(); 1395 argument = argumentFunc(); 1396 } 1397 catch (Exception e) 1398 { 1399 if (Fx.IsFatal(e)) 1400 { 1401 throw; 1402 } 1403 1404 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, e)); 1405 return false; 1406 } 1407 } 1408 1409 if (argument == null) 1410 { 1411 if (argumentExpression.NodeType == ExpressionType.MemberAccess) 1412 { 1413 MemberExpression memberExpression = (MemberExpression)argumentExpression; 1414 if (memberExpression.Member.MemberType == MemberTypes.Property) 1415 { 1416 RuntimeArgument runtimeArgument = ActivityUtilities.FindArgument(memberExpression.Member.Name, publicAccessor.ActivityMetadata.CurrentActivity); 1417 1418 if (runtimeArgument != null && TryGetInlinedReference(publicAccessor, runtimeArgument, isLocationExpression, out inlinedReference)) 1419 { 1420 return true; 1421 } 1422 } 1423 } 1424 1425 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, SR.SubexpressionResultWasNull(argumentExpression.Type))); 1426 return false; 1427 } 1428 else 1429 { 1430 if (argument.RuntimeArgument == null || !TryGetInlinedReference(publicAccessor, argument.RuntimeArgument, isLocationExpression, out inlinedReference)) 1431 { 1432 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(argumentExpression.Type))); 1433 return false; 1434 } 1435 else 1436 { 1437 return true; 1438 } 1439 } 1440 } 1441 TryRewriteArgumentGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1442 static bool TryRewriteArgumentGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1443 { 1444 // We verify that this is a method we are expecting (single parameter 1445 // of type ActivityContext). If not, we won't rewrite it at all 1446 // and will just let it fail at runtime. 1447 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1448 1449 if (argumentExpressions.Count == 1) 1450 { 1451 Expression contextExpression = argumentExpressions[0]; 1452 1453 if (contextExpression.Type == activityContextType) 1454 { 1455 LocationReference inlinedReference; 1456 if (TryGetInlinedArgumentReference(originalExpression, originalExpression.Object, out inlinedReference, publicAccessor, isLocationExpression)) 1457 { 1458 newExpression = Expression.Call(contextExpression, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1459 return true; 1460 } 1461 } 1462 } 1463 1464 newExpression = originalExpression; 1465 return false; 1466 } 1467 TryRewriteArgumentGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor)1468 static bool TryRewriteArgumentGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor) 1469 { 1470 // We verify that this is a method we are expecting (single parameter 1471 // of type ActivityContext). If not, we won't rewrite it at all 1472 // and will just let it fail at runtime. 1473 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1474 1475 if (argumentExpressions.Count == 1) 1476 { 1477 Expression contextExpression = argumentExpressions[0]; 1478 1479 if (contextExpression.Type == activityContextType) 1480 { 1481 LocationReference inlinedReference; 1482 if (TryGetInlinedArgumentReference(originalExpression, originalExpression.Object, out inlinedReference, publicAccessor, true)) 1483 { 1484 if (returnType == null) 1485 { 1486 newExpression = Expression.Call(Expression.Constant(inlinedReference, typeof(LocationReference)), locationReferenceGetLocationMethod, contextExpression); 1487 } 1488 else 1489 { 1490 newExpression = Expression.Call(contextExpression, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1491 } 1492 1493 return true; 1494 } 1495 } 1496 } 1497 1498 newExpression = originalExpression; 1499 return false; 1500 } 1501 TryRewriteLocationReferenceSubclassGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1502 static bool TryRewriteLocationReferenceSubclassGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1503 { 1504 // We verify that this is a method we are expecting (single parameter 1505 // of type ActivityContext). If not, we won't rewrite it at all 1506 // and will just let it fail at runtime. 1507 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1508 1509 if (argumentExpressions.Count == 1) 1510 { 1511 Expression contextExpression = argumentExpressions[0]; 1512 1513 if (contextExpression.Type == activityContextType) 1514 { 1515 LocationReference inlinedReference; 1516 if (TryGetInlinedLocationReference(originalExpression, originalExpression.Object, out inlinedReference, publicAccessor, isLocationExpression)) 1517 { 1518 newExpression = Expression.Call(contextExpression, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1519 return true; 1520 } 1521 } 1522 } 1523 1524 newExpression = originalExpression; 1525 return false; 1526 } 1527 TryRewriteLocationReferenceSubclassGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor)1528 static bool TryRewriteLocationReferenceSubclassGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor) 1529 { 1530 // We verify that this is a method we are expecting (single parameter 1531 // of type ActivityContext). If not, we won't rewrite it at all 1532 // and will just let it fail at runtime. 1533 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1534 1535 if (argumentExpressions.Count == 1) 1536 { 1537 Expression contextExpression = argumentExpressions[0]; 1538 1539 if (contextExpression.Type == activityContextType) 1540 { 1541 LocationReference inlinedReference; 1542 if (TryGetInlinedLocationReference(originalExpression, originalExpression.Object, out inlinedReference, publicAccessor, true)) 1543 { 1544 if (returnType == null) 1545 { 1546 newExpression = Expression.Call(Expression.Constant(inlinedReference, typeof(LocationReference)), locationReferenceGetLocationMethod, originalExpression.Arguments[0]); 1547 } 1548 else 1549 { 1550 newExpression = Expression.Call(contextExpression, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1551 } 1552 1553 return true; 1554 } 1555 } 1556 } 1557 1558 newExpression = originalExpression; 1559 return false; 1560 } 1561 CustomMemberResolver(Expression expression, out object memberValue)1562 static bool CustomMemberResolver(Expression expression, out object memberValue) 1563 { 1564 memberValue = null; 1565 1566 switch (expression.NodeType) 1567 { 1568 case ExpressionType.Constant: 1569 ConstantExpression constantExpression = expression as ConstantExpression; 1570 memberValue = constantExpression.Value; 1571 // memberValue = null means: 1572 // 1. The expression does not follow the common patterns(local, field or property) 1573 // which we optimize(do not compile using Linq compiler) and try to resolve directly in this method 1574 // OR 2. The expression actually resolved to null. 1575 // In both these cases, we compile the expression and run it so that we have a single error path. 1576 return memberValue != null; 1577 1578 case ExpressionType.MemberAccess: 1579 MemberExpression memberExpression = expression as MemberExpression; 1580 if (memberExpression.Expression != null) 1581 { 1582 CustomMemberResolver(memberExpression.Expression, out memberValue); 1583 memberValue = GetMemberValue(memberExpression.Member, memberValue); 1584 } 1585 return memberValue != null; 1586 1587 default: 1588 return false; 1589 } 1590 } 1591 GetMemberValue(MemberInfo memberInfo, object owner)1592 static object GetMemberValue(MemberInfo memberInfo, object owner) 1593 { 1594 if (owner == null) 1595 { 1596 // We do not want to throw any exceptions here. We 1597 // will just do the regular compile in this case. 1598 return null; 1599 } 1600 1601 MemberTypes memberType = memberInfo.MemberType; 1602 if (memberType == MemberTypes.Property) 1603 { 1604 PropertyInfo propertyInfo = memberInfo as PropertyInfo; 1605 return propertyInfo.GetValue(owner, null); 1606 1607 } 1608 else if (memberType == MemberTypes.Field) 1609 { 1610 FieldInfo fieldInfo = memberInfo as FieldInfo; 1611 return fieldInfo.GetValue(owner); 1612 } 1613 return null; 1614 } 1615 TryGetInlinedLocationReference(MethodCallExpression originalExpression, Expression locationReferenceExpression, out LocationReference inlinedReference, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1616 static bool TryGetInlinedLocationReference(MethodCallExpression originalExpression, Expression locationReferenceExpression, out LocationReference inlinedReference, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1617 { 1618 inlinedReference = null; 1619 1620 LocationReference locationReference = null; 1621 object tempLocationReference; 1622 if (CustomMemberResolver(locationReferenceExpression, out tempLocationReference) && tempLocationReference is LocationReference) 1623 { 1624 locationReference = (LocationReference)tempLocationReference; 1625 } 1626 else 1627 { 1628 try 1629 { 1630 Expression<Func<LocationReference>> locationReferenceLambda = Expression.Lambda<Func<LocationReference>>(locationReferenceExpression); 1631 Func<LocationReference> locationReferenceFunc = locationReferenceLambda.Compile(); 1632 locationReference = locationReferenceFunc(); 1633 } 1634 catch (Exception e) 1635 { 1636 if (Fx.IsFatal(e)) 1637 { 1638 throw; 1639 } 1640 1641 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, e)); 1642 return false; 1643 } 1644 } 1645 1646 if (locationReference == null) 1647 { 1648 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, SR.SubexpressionResultWasNull(locationReferenceExpression.Type))); 1649 return false; 1650 } 1651 else if (!TryGetInlinedReference(publicAccessor, locationReference, isLocationExpression, out inlinedReference)) 1652 { 1653 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(locationReferenceExpression.Type))); 1654 return false; 1655 } 1656 else 1657 { 1658 return true; 1659 } 1660 } 1661 TryRewriteActivityContextGetValueCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1662 static bool TryRewriteActivityContextGetValueCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1663 { 1664 newExpression = originalExpression; 1665 1666 LocationReference inlinedReference = null; 1667 1668 // We verify that this is a method we are expecting (single parameter 1669 // of either LocationReference or Argument type). If not, we won't 1670 // rewrite it at all and will just let it fail at runtime. 1671 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1672 1673 if (argumentExpressions.Count == 1) 1674 { 1675 Expression parameterExpression = argumentExpressions[0]; 1676 1677 if (TypeHelper.AreTypesCompatible(parameterExpression.Type, typeof(Argument))) 1678 { 1679 if (!TryGetInlinedArgumentReference(originalExpression, parameterExpression, out inlinedReference, publicAccessor, isLocationExpression)) 1680 { 1681 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(parameterExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(parameterExpression.Type))); 1682 return false; 1683 } 1684 } 1685 else if (TypeHelper.AreTypesCompatible(parameterExpression.Type, typeof(LocationReference))) 1686 { 1687 if (!TryGetInlinedLocationReference(originalExpression, parameterExpression, out inlinedReference, publicAccessor, isLocationExpression)) 1688 { 1689 publicAccessor.ActivityMetadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(parameterExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(parameterExpression.Type))); 1690 return false; 1691 } 1692 } 1693 } 1694 1695 if (inlinedReference != null) 1696 { 1697 newExpression = Expression.Call(originalExpression.Object, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1698 return true; 1699 } 1700 1701 return false; 1702 } 1703 TryRewriteActivityContextGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor)1704 static bool TryRewriteActivityContextGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor) 1705 { 1706 // We verify that this is a method we are expecting (single parameter 1707 // of LocationReference type). If not, we won't rewrite it at all 1708 // and will just let it fail at runtime. 1709 ReadOnlyCollection<Expression> argumentExpressions = originalExpression.Arguments; 1710 1711 if (argumentExpressions.Count == 1) 1712 { 1713 Expression locationReference = argumentExpressions[0]; 1714 1715 if (TypeHelper.AreTypesCompatible(locationReference.Type, locationReferenceType)) 1716 { 1717 LocationReference inlinedReference; 1718 if (TryGetInlinedLocationReference(originalExpression, originalExpression.Arguments[0], out inlinedReference, publicAccessor, true)) 1719 { 1720 newExpression = Expression.Call(originalExpression.Object, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference, typeof(LocationReference))); 1721 return true; 1722 } 1723 } 1724 } 1725 1726 newExpression = originalExpression; 1727 return false; 1728 } 1729 1730 // Local perf testing leads to the following preference for matching method infos: 1731 // * object.ReferenceEquals(info1, info2) is the fastest 1732 // * info1.Name == "MethodName" is a close second 1733 // * object.ReferenceEquals(info1, type.GetMethod("MethodName")) is very slow by comparison 1734 // * object.ReferenceEquals(info1, genericMethodDefinition.MakeGenericMethod(typeParameter)) is also very 1735 // slow by comparison TryRewriteMethodCall(MethodCallExpression methodCall, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression)1736 static bool TryRewriteMethodCall(MethodCallExpression methodCall, out Expression newExpression, CodeActivityPublicEnvironmentAccessor publicAccessor, bool isLocationExpression) 1737 { 1738 // NOTE: Here's the set of method call conversions/rewrites that we are 1739 // performing. The left hand side of the "=>" is the pattern that from 1740 // the original expression using the following shorthand for instances of 1741 // types: 1742 // ctx = ActivityContext 1743 // inArg = InArgument<T> 1744 // inOutArg = InOutArgument<T> 1745 // outArg = OutArgument<T> 1746 // arg = Argument 1747 // runtimeArg = RuntimeArgument 1748 // ref = LocationReference (and subclasses) 1749 // 1750 // The right hand side of the "=>" shows the rewritten method call. When 1751 // the same symbol shows up on both sides that means we will use the same 1752 // expression (IE - ref.Get(ctx) => ctx.GetValue<T>(inline) means that the 1753 // expression for ctx on the left side is the same expression we should use 1754 // on the right side). 1755 // 1756 // "inline" is used in the right hand side to signify the inlined location 1757 // reference. Except where explicitly called out, this is the inlined 1758 // version of the LocationReference (or subclass) from the left hand side. 1759 // 1760 // If the left-hand-side method is Get/GetValue methods, and isLocationExpression 1761 // is false, we create a read-only InlinedLocationReference, which will produce 1762 // a RuntimeArgument<T> with ArgumentDirection.In. 1763 // Otherwise, we create a full-access InlinedLocationReference, which will produce 1764 // a RuntimeArgument<Location<T>> with ArgumentDirection.In. 1765 // 1766 // Finally, "(new)" signifies that the method we are looking for hides a 1767 // method with the same signature on one of the base classes. 1768 // 1769 // ActivityContext 1770 // ctx.GetValue<T>(inArg) => ctx.GetValue<T>(inline) inline = Inline(inArg.RuntimeArgument) 1771 // ctx.GetValue<T>(inOutArg) => ctx.GetValue<T>(inline) inline = Inline(inOutArg.RuntimeArgument) 1772 // ctx.GetValue<T>(outArg) => ctx.GetValue<T>(inline) inline = Inline(outArg.RuntimeArgument) 1773 // ctx.GetValue(arg) => ctx.GetValue<object>(inline) inline = Inline(arg.RuntimeArgument) 1774 // ctx.GetValue(runtimeArg) => ctx.GetValue<object>(inline) 1775 // ctx.GetValue<T>(ref) => ctx.GetValue<T>(inline) 1776 // ctx.GetLocation<T>(ref) => ctx.GetLocation<T>(inline) 1777 // 1778 // LocationReference 1779 // ref.GetLocation(ctx) => inline.GetLocation(ctx) 1780 // 1781 // RuntimeArgument : LocationReference 1782 // ref.Get(ctx) => ctx.GetValue<object>(inline) 1783 // ref.Get<T>(ctx) => ctx.GetValue<T>(inline) 1784 // 1785 // Argument 1786 // arg.Get(ctx) => ctx.GetValue<object>(inline) inline = Inline(arg.RuntimeArgument) 1787 // arg.Get<T>(ctx) => ctx.GetValue<T>(inline) inline = Inline(arg.RuntimeArgument) 1788 // arg.GetLocation(ctx) => inline.GetLocation(ctx) inline = Inline(arg.RuntimeArgument) 1789 // 1790 // InArgument<T> : Argument 1791 // (new) arg.Get(ctx) => ctx.GetValue<T>(inline) inline = Inline(arg.RuntimeArgument) 1792 // 1793 // InOutArgument<T> : Argument 1794 // (new) arg.Get(ctx) => ctx.GetValue<T>(inline) inline = Inline(arg.RuntimeArgument) 1795 // (new) arg.GetLocation<T>(ctx) => ctx.GetLocation<T>(inline) inline = Inline(arg.RuntimeArgument) 1796 // 1797 // OutArgument<T> : Argument 1798 // (new) arg.Get(ctx) => ctx.GetValue<T>(inline) inline = Inline(arg.RuntimeArgument) 1799 // (new) arg.GetLocation<T>(ctx) => ctx.GetLocation<T>(inline) inline = Inline(arg.RuntimeArgument) 1800 // 1801 // Variable : LocationReference 1802 // ref.Get(ctx) => ctx.GetValue<object>(inline) 1803 // 1804 // Variable<T> : Variable 1805 // (new) ref.Get(ctx) => ctx.GetValue<T>(inline) 1806 // (new) ref.GetLocation(ctx) => ctx.GetLocation<T>(inline) 1807 // 1808 // DelegateArgument : LocationReference 1809 // ref.Get(ctx) => ctx.GetValue<object>(inline) 1810 // 1811 // DelegateInArgument<T> : DelegateArgument 1812 // (new) ref.Get(ctx) => ctx.GetValue<T>(inline) 1813 // 1814 // DelegateOutArgument<T> : DelegateArgument 1815 // (new) ref.Get(ctx) => ctx.GetValue<T>(inline) 1816 // (new) ref.GetLocation(ctx) => ctx.GetLocation<T>(inline) 1817 1818 MethodInfo targetMethod = methodCall.Method; 1819 Type targetObjectType = targetMethod.DeclaringType; 1820 1821 if (targetObjectType.IsGenericType) 1822 { 1823 // All of these methods are non-generic methods (they don't introduce a new 1824 // type parameter), but they do make use of the type parameter of the 1825 // generic declaring type. Because of that we can't do MethodInfo comparison 1826 // and fall back to string comparison. 1827 Type targetObjectGenericType = targetObjectType.GetGenericTypeDefinition(); 1828 1829 if (targetObjectGenericType == variableGenericType) 1830 { 1831 if (targetMethod.Name == "Get") 1832 { 1833 return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor, isLocationExpression); 1834 } 1835 else if (targetMethod.Name == "GetLocation") 1836 { 1837 return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor); 1838 } 1839 } 1840 else if (targetObjectGenericType == inArgumentGenericType) 1841 { 1842 if (targetMethod.Name == "Get") 1843 { 1844 return TryRewriteArgumentGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor, isLocationExpression); 1845 } 1846 } 1847 else if (targetObjectGenericType == outArgumentGenericType || targetObjectGenericType == inOutArgumentGenericType) 1848 { 1849 if (targetMethod.Name == "Get") 1850 { 1851 return TryRewriteArgumentGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor, isLocationExpression); 1852 } 1853 else if (targetMethod.Name == "GetLocation") 1854 { 1855 return TryRewriteArgumentGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor); 1856 } 1857 } 1858 else if (targetObjectGenericType == delegateInArgumentGenericType) 1859 { 1860 if (targetMethod.Name == "Get") 1861 { 1862 return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor, isLocationExpression); 1863 } 1864 } 1865 else if (targetObjectGenericType == delegateOutArgumentGenericType) 1866 { 1867 if (targetMethod.Name == "Get") 1868 { 1869 return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor, isLocationExpression); 1870 } 1871 else if (targetMethod.Name == "GetLocation") 1872 { 1873 return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, publicAccessor); 1874 } 1875 } 1876 } 1877 else 1878 { 1879 if (targetObjectType == variableType) 1880 { 1881 if (object.ReferenceEquals(targetMethod, variableGetMethod)) 1882 { 1883 return TryRewriteLocationReferenceSubclassGetCall(methodCall, TypeHelper.ObjectType, out newExpression, publicAccessor, isLocationExpression); 1884 } 1885 } 1886 else if (targetObjectType == delegateArgumentType) 1887 { 1888 if (object.ReferenceEquals(targetMethod, delegateArgumentGetMethod)) 1889 { 1890 return TryRewriteLocationReferenceSubclassGetCall(methodCall, TypeHelper.ObjectType, out newExpression, publicAccessor, isLocationExpression); 1891 } 1892 } 1893 else if (targetObjectType == activityContextType) 1894 { 1895 // We use the string comparison for these two because 1896 // we have several overloads of GetValue (some generic, 1897 // some not) and GetLocation is a generic method 1898 if (targetMethod.Name == "GetValue") 1899 { 1900 Type returnType = TypeHelper.ObjectType; 1901 1902 if (targetMethod.IsGenericMethod) 1903 { 1904 returnType = targetMethod.GetGenericArguments()[0]; 1905 } 1906 1907 return TryRewriteActivityContextGetValueCall(methodCall, returnType, out newExpression, publicAccessor, isLocationExpression); 1908 } 1909 else if (targetMethod.IsGenericMethod && targetMethod.Name == "GetLocation") 1910 { 1911 return TryRewriteActivityContextGetLocationCall(methodCall, targetMethod.GetGenericArguments()[0], out newExpression, publicAccessor); 1912 } 1913 } 1914 else if (targetObjectType == locationReferenceType) 1915 { 1916 if (object.ReferenceEquals(targetMethod, locationReferenceGetLocationMethod)) 1917 { 1918 return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, null, out newExpression, publicAccessor); 1919 } 1920 } 1921 else if (targetObjectType == runtimeArgumentType) 1922 { 1923 // We use string comparison here because we can 1924 // match both overloads with a single check. 1925 if (targetMethod.Name == "Get") 1926 { 1927 Type returnType = TypeHelper.ObjectType; 1928 1929 if (targetMethod.IsGenericMethod) 1930 { 1931 returnType = targetMethod.GetGenericArguments()[0]; 1932 } 1933 1934 return TryRewriteLocationReferenceSubclassGetCall(methodCall, returnType, out newExpression, publicAccessor, isLocationExpression); 1935 } 1936 } 1937 else if (targetObjectType == argumentType) 1938 { 1939 // We use string comparison here because we can 1940 // match both overloads with a single check. 1941 if (targetMethod.Name == "Get") 1942 { 1943 Type returnType = TypeHelper.ObjectType; 1944 1945 if (targetMethod.IsGenericMethod) 1946 { 1947 returnType = targetMethod.GetGenericArguments()[0]; 1948 } 1949 1950 return TryRewriteArgumentGetCall(methodCall, returnType, out newExpression, publicAccessor, isLocationExpression); 1951 } 1952 else if (object.ReferenceEquals(targetMethod, argumentGetLocationMethod)) 1953 { 1954 return TryRewriteArgumentGetLocationCall(methodCall, null, out newExpression, publicAccessor); 1955 } 1956 } 1957 } 1958 1959 // Here's the code for a method call that isn't on our "special" list 1960 newExpression = methodCall; 1961 1962 Expression objectExpression; 1963 IList<Expression> expressionList; 1964 1965 bool hasChanged = TryRewriteLambdaExpression(methodCall.Object, out objectExpression, publicAccessor); 1966 hasChanged |= TryRewriteLambdaExpressionCollection(methodCall.Arguments, out expressionList, publicAccessor); 1967 1968 if (hasChanged) 1969 { 1970 newExpression = Expression.Call(objectExpression, targetMethod, expressionList); 1971 } 1972 1973 return hasChanged; 1974 } 1975 RewriteNonCompiledExpressionTree(LambdaExpression originalLambdaExpression)1976 internal static Expression RewriteNonCompiledExpressionTree(LambdaExpression originalLambdaExpression) 1977 { 1978 ExpressionTreeRewriter expressionVisitor = new ExpressionTreeRewriter(); 1979 return expressionVisitor.Visit(Expression.Lambda( 1980 typeof(Func<,>).MakeGenericType(typeof(ActivityContext), originalLambdaExpression.ReturnType), 1981 originalLambdaExpression.Body, 1982 new ParameterExpression[] { ExpressionUtilities.RuntimeContextParameter })); 1983 } 1984 } 1985 } 1986