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