ExpressionUtilities.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / ExpressionUtilities.cs / 1305376 / ExpressionUtilities.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------

namespace System.Activities 
{
    using System; 
    using System.Collections.ObjectModel; 
    using System.ComponentModel;
    using System.Linq; 
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Runtime;
    using System.Runtime.Serialization; 
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis; 
 
    static class ExpressionUtilities
    { 
        public static ParameterExpression RuntimeContextParameter = Expression.Parameter(typeof(ActivityContext), "context");
        static Assembly linqAssembly = typeof(Func<>).Assembly;
        static MethodInfo createLocationFactoryGenericMethod = typeof(ExpressionUtilities).GetMethod("CreateLocationFactory");
        static MethodInfo propertyDescriptorGetValue; // PropertyDescriptor.GetValue 

 
        // Types cached for use in TryRewriteLambdaExpression 
        static Type inArgumentGenericType = typeof(InArgument<>);
        static Type outArgumentGenericType = typeof(OutArgument<>); 
        static Type inOutArgumentGenericType = typeof(InOutArgument<>);
        static Type variableGenericType = typeof(Variable<>);
        static Type delegateInArgumentGenericType = typeof(DelegateInArgument<>);
        static Type delegateOutArgumentGenericType = typeof(DelegateOutArgument<>); 
        static Type activityContextType = typeof(ActivityContext);
        static Type locationReferenceType = typeof(LocationReference); 
        static Type runtimeArgumentType = typeof(RuntimeArgument); 
        static Type argumentType = typeof(Argument);
        static Type variableType = typeof(Variable); 
        static Type delegateArgumentType = typeof(DelegateArgument);

        // MethodInfos cached for use in TryRewriteLambdaExpression
        static MethodInfo activityContextGetValueGenericMethod = typeof(ActivityContext).GetMethod("GetValue", new Type[] { typeof(LocationReference) }); 
        static MethodInfo activityContextGetLocationGenericMethod = typeof(ActivityContext).GetMethod("GetLocation", new Type[] { typeof(LocationReference) });
        static MethodInfo locationReferenceGetLocationMethod = typeof(LocationReference).GetMethod("GetLocation", new Type[] { typeof(ActivityContext) }); 
        static MethodInfo argumentGetLocationMethod = typeof(Argument).GetMethod("GetLocation", new Type[] { typeof(ActivityContext) }); 
        static MethodInfo variableGetMethod = typeof(Variable).GetMethod("Get", new Type[] { typeof(ActivityContext) });
        static MethodInfo delegateArgumentGetMethod = typeof(DelegateArgument).GetMethod("Get", new Type[] { typeof(ActivityContext) }); 

        static MethodInfo PropertyDescriptorGetValue
        {
            get 
            {
                if (propertyDescriptorGetValue == null) 
                { 
                    propertyDescriptorGetValue = typeof(PropertyDescriptor).GetMethod("GetValue");
                } 

                return propertyDescriptorGetValue;
            }
        } 

        public static Expression CreateIdentifierExpression(LocationReference locationReference) 
        { 
            return Expression.Call(RuntimeContextParameter, activityContextGetValueGenericMethod.MakeGenericMethod(locationReference.Type), Expression.Constant(locationReference));
        } 

        public static bool IsLocation(LambdaExpression expression, Type targetType, out string extraErrorMessage)
        {
            extraErrorMessage = null; 
            Expression body = expression.Body;
 
            if (targetType != null && body.Type != targetType) 
            {
                // eg) LambdaReference((env) => strVar.Get(env)) 
                // you can have an expressionTree whose LambdaExpression.ReturnType == IComparable,
                // while its LambdaExpression.Body.Type == String
                // and not ever have Convert node in the tree.
                extraErrorMessage = SR.MustMatchReferenceExpressionReturnType; 
                return false;
            } 
 
            switch (body.NodeType)
            { 
                case ExpressionType.ArrayIndex:
                    return true;

                case ExpressionType.MemberAccess: 
                    // This also handles variables, which are emitted as "context.GetLocation("v").Value"
                    MemberExpression memberExpression = (MemberExpression)body; 
                    MemberTypes memberType = memberExpression.Member.MemberType; 
                    if (memberType == MemberTypes.Field)
                    { 
                        FieldInfo fieldInfo = (FieldInfo)memberExpression.Member;
                        if (fieldInfo.IsInitOnly)
                        {
                            // readOnly field 
                            return false;
                        } 
                        return true; 
                    }
                    else if (memberType == MemberTypes.Property) 
                    {
                        PropertyInfo propertyInfo = (PropertyInfo)memberExpression.Member;
                        if (!propertyInfo.CanWrite)
                        { 
                            // no Setter
                            return false; 
                        } 
                        return true;
                    } 
                    break;

                case ExpressionType.Call:
                    // Depends on the method being called. 
                    //     System.Array.Get --> multi-dimensional array
                    //     get_Item --> might be an indexer property if it's special name & default etc. 
 
                    MethodCallExpression callExpression = (MethodCallExpression)body;
                    MethodInfo method = callExpression.Method; 

                    Type declaringType = method.DeclaringType;
                    if (declaringType.BaseType == TypeHelper.ArrayType && method.Name == "Get")
                    { 
                        return true;
                    } 
                    else if (method.IsSpecialName && method.Name.StartsWith("get_", StringComparison.Ordinal)) 
                    {
                        return true; 
                    }
                    else if (method.Name == "GetValue" && declaringType == activityContextType)
                    {
                        return true; 
                    }
                    else if (method.Name == "Get" && declaringType.IsGenericType) 
                    { 
                        Type declaringTypeGenericDefinition = declaringType.GetGenericTypeDefinition();
 
                        if (declaringTypeGenericDefinition == inOutArgumentGenericType ||
                            declaringTypeGenericDefinition == outArgumentGenericType)
                        {
                            return true; 
                        }
                    } 
                    break; 

                case ExpressionType.Convert: 
                    // a would-be-valid Location expression that is type converted is treated invalid
                    extraErrorMessage = SR.MustMatchReferenceExpressionReturnType;
                    return false;
            } 
            return false;
        } 
 
        public static LocationFactory CreateLocationFactory(LambdaExpression expression)
        { 
            Expression body = expression.Body;

            switch (body.NodeType)
            { 
                case ExpressionType.ArrayIndex:
                    return new ArrayLocationFactory(expression); 
 
                case ExpressionType.MemberAccess:
                    // This also handles variables, which are emitted as "context.GetLocation("v").Value" 
                    MemberTypes memberType = ((MemberExpression)body).Member.MemberType;
                    if (memberType == MemberTypes.Field)
                    {
                        return new FieldLocationFactory(expression); 
                    }
                    else if (memberType == MemberTypes.Property) 
                    { 
                        return new PropertyLocationFactory(expression);
                    } 
                    else
                    {
                        throw FxTrace.Exception.AsError(new NotSupportedException("Lvalues of member type " + memberType));
                    } 

                case ExpressionType.Call: 
                    // Depends on the method being called. 
                    //     System.Array.Get --> multi-dimensional array
                    //     get_Item --> might be an indexer property if it's special name & default etc. 

                    MethodCallExpression callExpression = (MethodCallExpression)body;
                    MethodInfo method = callExpression.Method;
 
                    Type declaringType = method.DeclaringType;
                    if (declaringType.BaseType == TypeHelper.ArrayType && method.Name == "Get") 
                    { 
                        return new MultidimensionalArrayLocationFactory(expression);
                    } 
                    else if (method.IsSpecialName && method.Name.StartsWith("get_", StringComparison.Ordinal))
                    {
                        return new IndexerLocationFactory(expression);
                    } 
                    else if (method.Name == "GetValue" && declaringType == activityContextType)
                    { 
                        return new LocationReferenceFactory(callExpression.Arguments[0], expression.Parameters); 
                    }
                    else if (method.Name == "Get" && declaringType.IsGenericType) 
                    {
                        Type declaringTypeGenericDefinition = declaringType.GetGenericTypeDefinition();

                        if (declaringTypeGenericDefinition == inOutArgumentGenericType || 
                            declaringTypeGenericDefinition == outArgumentGenericType)
                        { 
                            return new ArgumentFactory(callExpression.Object, expression.Parameters); 
                        }
                    } 

                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidExpressionForLocation(body.NodeType)));

                default: 
                    throw FxTrace.Exception.AsError(new InvalidOperationException(SR.InvalidExpressionForLocation(body.NodeType)));
            } 
        } 

        static LocationFactory CreateParentReference(Expression expression, ReadOnlyCollection lambdaParameters) 
        {
            // create a LambdaExpression to get access to the expression
            int parameterCount = lambdaParameters.Count;
            Type genericFuncType = linqAssembly.GetType("System.Func`" + (parameterCount + 1), true); 
            Type[] delegateParameterTypes = new Type[parameterCount + 1];
 
            for (int i = 0; i < parameterCount; ++i) 
            {
                delegateParameterTypes[i] = lambdaParameters[i].Type; 
            }
            delegateParameterTypes[parameterCount] = expression.Type;
            Type funcType = genericFuncType.MakeGenericType(delegateParameterTypes);
            LambdaExpression parentLambda = Expression.Lambda(funcType, expression, lambdaParameters); 

            // call CreateLocationFactory(parentLambda); 
            MethodInfo typedMethod = createLocationFactoryGenericMethod.MakeGenericMethod(expression.Type); 
            return (LocationFactory)typedMethod.Invoke(null, new object[] { parentLambda });
        } 

        static Func Compile(Expression objectExpression, ReadOnlyCollection parametersCollection)
        {
            ParameterExpression[] parameters = null; 
            if (parametersCollection != null)
            { 
                parameters = parametersCollection.ToArray(); 
            }
 
            Expression> objectLambda = Expression.Lambda>(objectExpression, parameters);
            return objectLambda.Compile();
        }
 
        static T Evaluate(Expression objectExpression, ReadOnlyCollection parametersCollection, ActivityContext context)
        { 
            Func objectFunc = Compile(objectExpression, parametersCollection); 
            return objectFunc(context);
        } 

        // for single-dimensional arrays
        class ArrayLocationFactory : LocationFactory
        { 
            Func arrayFunction;
            Func indexFunction; 
 
            public ArrayLocationFactory(LambdaExpression expression)
            { 
                Fx.Assert(expression.Body.NodeType == ExpressionType.ArrayIndex, "ArrayIndex expression required");
                BinaryExpression arrayIndexExpression = (BinaryExpression)expression.Body;

                this.arrayFunction = ExpressionUtilities.Compile(arrayIndexExpression.Left, expression.Parameters); 
                this.indexFunction = ExpressionUtilities.Compile(arrayIndexExpression.Right, expression.Parameters);
            } 
 
            public override Location CreateLocation(ActivityContext context)
            { 
                return new ArrayLocation(this.arrayFunction(context), this.indexFunction(context));
            }

            [DataContract] 
            class ArrayLocation : Location
            { 
                [DataMember] 
                T[] array;
 
                [DataMember(EmitDefaultValue = false)]
                int index;

                public ArrayLocation(T[] array, int index) 
                    : base()
                { 
                    this.array = array; 
                    this.index = index;
                } 

                public override T Value
                {
                    get 
                    {
                        return this.array[this.index]; 
                    } 
                    set
                    { 
                        this.array[this.index] = value;
                    }
                }
            } 
        }
 
        class FieldLocationFactory : LocationFactory 
        {
            FieldInfo fieldInfo; 
            Func ownerFunction;
            LocationFactory parentFactory;

            public FieldLocationFactory(LambdaExpression expression) 
            {
                Fx.Assert(expression.Body.NodeType == ExpressionType.MemberAccess, "field expression required"); 
                MemberExpression memberExpression = (MemberExpression)expression.Body; 

                Fx.Assert(memberExpression.Member.MemberType == MemberTypes.Field, "member field expected"); 
                this.fieldInfo = (FieldInfo)memberExpression.Member;

                if (this.fieldInfo.IsStatic)
                { 
                    this.ownerFunction = null;
                } 
                else 
                {
                    this.ownerFunction = ExpressionUtilities.Compile( 
                    Expression.Convert(memberExpression.Expression, TypeHelper.ObjectType), expression.Parameters);
                }

                if (this.fieldInfo.DeclaringType.IsValueType) 
                {
                    // may want to set a struct, so we need to make an expression in order to set the parent 
                    parentFactory = CreateParentReference(memberExpression.Expression, expression.Parameters); 
                }
            } 

            public override Location CreateLocation(ActivityContext context)
            {
                object owner = null; 
                if (this.ownerFunction != null)
                { 
                    owner = this.ownerFunction(context); 
                }
 
                Location parent = null;
                if (parentFactory != null)
                {
                    parent = parentFactory.CreateLocation(context); 
                }
                return new FieldLocation(this.fieldInfo, owner, parent); 
            } 

            [DataContract] 
            class FieldLocation : Location
            {
                [DataMember]
                FieldInfo fieldInfo; 

                [DataMember(EmitDefaultValue = false)] 
                object owner; 

                [DataMember(EmitDefaultValue = false)] 
                Location parent;

                public FieldLocation(FieldInfo fieldInfo, object owner, Location parent)
                    : base() 
                {
                    this.fieldInfo = fieldInfo; 
                    this.owner = owner; 
                    this.parent = parent;
                } 

                [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes,
                    Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")]
                public override T Value 
                {
                    get 
                    { 
                        if (this.owner == null && !this.fieldInfo.IsStatic)
                        { 
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.fieldInfo.Name)));
                        }

                        return (T)this.fieldInfo.GetValue(this.owner); 
                    }
                    set 
                    { 
                        if (this.owner == null && !this.fieldInfo.IsStatic)
                        { 
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.fieldInfo.Name)));
                        }

                        this.fieldInfo.SetValue(this.owner, value); 
                        if (this.parent != null)
                        { 
                            // Looks like we are trying to set a field on a struct 
                            // Calling SetValue simply sets the field on the local copy of the struct, which is not very helpful
                            // Since we have a copy, assign it back to the parent 
                            this.parent.Value = this.owner;
                        }
                    }
                } 
            }
        } 
 
        class ArgumentFactory : LocationFactory
        { 
            Func argumentFunction;

            public ArgumentFactory(Expression argumentExpression, ReadOnlyCollection expressionParameters)
            { 
                this.argumentFunction = ExpressionUtilities.Compile(argumentExpression, expressionParameters);
            } 
 
            public override Location CreateLocation(ActivityContext context)
            { 
                Argument argument = this.argumentFunction(context);

                return argument.RuntimeArgument.GetLocation(context) as Location;
            } 
        }
 
        class LocationReferenceFactory : LocationFactory 
        {
            Func locationReferenceFunction; 

            public LocationReferenceFactory(Expression locationReferenceExpression, ReadOnlyCollection expressionParameters)
            {
                this.locationReferenceFunction = ExpressionUtilities.Compile(locationReferenceExpression, expressionParameters); 
            }
 
            public override Location CreateLocation(ActivityContext context) 
            {
                LocationReference locationReference = this.locationReferenceFunction(context); 
                return locationReference.GetLocation(context) as Location;
            }
        }
 
        class IndexerLocationFactory : LocationFactory
        { 
            MethodInfo getItemMethod; 
            string indexerName;
            MethodInfo setItemMethod; 
            Func[] setItemArgumentFunctions;
            Func targetObjectFunction;

            public IndexerLocationFactory(LambdaExpression expression) 
            {
                Fx.Assert(expression.Body.NodeType == ExpressionType.Call, "Call expression required."); 
 
                MethodCallExpression callExpression = (MethodCallExpression)expression.Body;
                this.getItemMethod = callExpression.Method; 

                Fx.Assert(this.getItemMethod.IsSpecialName && this.getItemMethod.Name.StartsWith("get_", StringComparison.Ordinal), "Special get_Item method required.");

                //  Get the set_Item accessor for the same set of parameter/return types if any. 
                this.indexerName = this.getItemMethod.Name.Substring(4);
                string setItemName = "set_" + this.indexerName; 
                ParameterInfo[] getItemParameters = this.getItemMethod.GetParameters(); 
                Type[] setItemParameterTypes = new Type[getItemParameters.Length + 1];
 
                for (int i = 0; i < getItemParameters.Length; i++)
                {
                    setItemParameterTypes[i] = getItemParameters[i].ParameterType;
                } 
                setItemParameterTypes[getItemParameters.Length] = this.getItemMethod.ReturnType;
 
                this.setItemMethod = this.getItemMethod.DeclaringType.GetMethod( 
                    setItemName, BindingFlags.Public | BindingFlags.Instance, null, setItemParameterTypes, null);
 
                if (this.setItemMethod != null)
                {
                    //  Get the target object and all the setter's arguments
                    //  (minus the actual value to be set). 
                    this.targetObjectFunction = ExpressionUtilities.Compile(callExpression.Object, expression.Parameters);
 
                    this.setItemArgumentFunctions = new Func[callExpression.Arguments.Count]; 
                    for (int i = 0; i < callExpression.Arguments.Count; i++)
                    { 
                        // convert value types to objects since Linq doesn't do it automatically
                        Expression argument = callExpression.Arguments[i];
                        if (argument.Type.IsValueType)
                        { 
                            argument = Expression.Convert(argument, TypeHelper.ObjectType);
                        } 
                        this.setItemArgumentFunctions[i] = ExpressionUtilities.Compile(argument, expression.Parameters); 
                    }
                } 
            }

            public override Location CreateLocation(ActivityContext context)
            { 
                object targetObject = null;
                object[] setItemArguments = null; 
 
                if (this.setItemMethod != null)
                { 
                    targetObject = this.targetObjectFunction(context);

                    setItemArguments = new object[this.setItemArgumentFunctions.Length];
 
                    for (int i = 0; i < this.setItemArgumentFunctions.Length; i++)
                    { 
                        setItemArguments[i] = this.setItemArgumentFunctions[i](context); 
                    }
                } 

                return new IndexerLocation(this.indexerName, this.getItemMethod, this.setItemMethod, targetObject, setItemArguments);
            }
 
            [DataContract]
            class IndexerLocation : Location 
            { 
                [DataMember]
                string indexerName; 

                [DataMember(EmitDefaultValue = false)]
                MethodInfo getItemMethod;
 
                [DataMember(EmitDefaultValue = false)]
                MethodInfo setItemMethod; 
 
                [DataMember(EmitDefaultValue = false)]
                object targetObject; 

                [DataMember(EmitDefaultValue = false)]
                object[] setItemArguments;
 
                public IndexerLocation(string indexerName, MethodInfo getItemMethod, MethodInfo setItemMethod,
                    object targetObject, object[] getItemArguments) 
                    : base() 
                {
                    this.indexerName = indexerName; 
                    this.getItemMethod = getItemMethod;
                    this.setItemMethod = setItemMethod;
                    this.targetObject = targetObject;
                    this.setItemArguments = getItemArguments; 
                }
 
                [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes, 
                Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")]
                public override T Value 
                {
                    get
                    {
                        if (this.targetObject == null && !this.getItemMethod.IsStatic) 
                        {
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.getItemMethod.Name))); 
                        } 

                        return (T)this.getItemMethod.Invoke(this.targetObject, this.setItemArguments); 
                    }

                    set
                    { 

                        if (this.setItemMethod == null) 
                        { 
                            string targetObjectTypeName = this.targetObject.GetType().Name;
                            throw FxTrace.Exception.AsError(new InvalidOperationException( 
                                SR.MissingSetAccessorForIndexer(this.indexerName, targetObjectTypeName)));
                        }

                        if (this.targetObject == null && !this.setItemMethod.IsStatic) 
                        {
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.setItemMethod.Name))); 
                        } 

                        object[] localSetItemArguments = new object[this.setItemArguments.Length + 1]; 
                        Array.ConstrainedCopy(this.setItemArguments, 0, localSetItemArguments, 0, this.setItemArguments.Length);
                        localSetItemArguments[localSetItemArguments.Length - 1] = value;

                        this.setItemMethod.Invoke(this.targetObject, localSetItemArguments); 
                    }
                } 
            } 
        }
 
        class MultidimensionalArrayLocationFactory : LocationFactory
        {
            Func arrayFunction;
            Func[] indexFunctions; 

            public MultidimensionalArrayLocationFactory(LambdaExpression expression) 
            { 
                Fx.Assert(expression.Body.NodeType == ExpressionType.Call, "Call expression required.");
                MethodCallExpression callExpression = (MethodCallExpression)expression.Body; 

                this.arrayFunction = ExpressionUtilities.Compile(
                    callExpression.Object, expression.Parameters);
 
                this.indexFunctions = new Func[callExpression.Arguments.Count];
                for (int i = 0; i < this.indexFunctions.Length; i++) 
                { 
                    this.indexFunctions[i] = ExpressionUtilities.Compile(
                        callExpression.Arguments[i], expression.Parameters); 
                }
            }

            public override Location CreateLocation(ActivityContext context) 
            {
                int[] indices = new int[this.indexFunctions.Length]; 
                for (int i = 0; i < indices.Length; i++) 
                {
                    indices[i] = this.indexFunctions[i](context); 
                }
                return new MultidimensionalArrayLocation(this.arrayFunction(context), indices);
            }
 
            [DataContract]
            class MultidimensionalArrayLocation : Location 
            { 
                [DataMember]
                Array array; 

                [DataMember]
                int[] indices;
 
                public MultidimensionalArrayLocation(Array array, int[] indices)
                    : base() 
                { 
                    this.array = array;
                    this.indices = indices; 
                }

                public override T Value
                { 
                    get
                    { 
                        return (T)this.array.GetValue(this.indices); 
                    }
 
                    set
                    {
                        this.array.SetValue(value, this.indices);
                    } 
                }
            } 
        } 

        class PropertyLocationFactory : LocationFactory 
        {
            Func ownerFunction;
            PropertyInfo propertyInfo;
            LocationFactory parentFactory; 

            public PropertyLocationFactory(LambdaExpression expression) 
            { 
                Fx.Assert(expression.Body.NodeType == ExpressionType.MemberAccess, "member access expression required");
                MemberExpression memberExpression = (MemberExpression)expression.Body; 

                Fx.Assert(memberExpression.Member.MemberType == MemberTypes.Property, "property access expression expected");
                this.propertyInfo = (PropertyInfo)memberExpression.Member;
 
                if (memberExpression.Expression == null)
                { 
                    // static property 
                    this.ownerFunction = null;
                } 
                else
                {
                    this.ownerFunction = ExpressionUtilities.Compile(
                        Expression.Convert(memberExpression.Expression, TypeHelper.ObjectType), expression.Parameters); 
                }
 
                if (this.propertyInfo.DeclaringType.IsValueType) 
                {
                    // may want to set a struct, so we need to make an expression in order to set the parent 
                    parentFactory = CreateParentReference(memberExpression.Expression, expression.Parameters);
                }
            }
 
            public override Location CreateLocation(ActivityContext context)
            { 
                object owner = null; 
                if(this.ownerFunction != null)
                { 
                    owner = this.ownerFunction(context);
                }

                Location parent = null; 
                if (parentFactory != null)
                { 
                    parent = parentFactory.CreateLocation(context); 
                }
                return new PropertyLocation(this.propertyInfo, owner, parent); 
            }

            [DataContract]
            class PropertyLocation : Location 
            {
                [DataMember(EmitDefaultValue = false)] 
                object owner; 

                [DataMember] 
                PropertyInfo propertyInfo;

                [DataMember(EmitDefaultValue = false)]
                Location parent; 

                public PropertyLocation(PropertyInfo propertyInfo, object owner, Location parent) 
                    : base() 
                {
                    this.propertyInfo = propertyInfo; 
                    this.owner = owner;
                    this.parent = parent;
                }
 
                [SuppressMessage(FxCop.Category.Usage, FxCop.Rule.DoNotRaiseReservedExceptionTypes,
                Justification = "Need to raise NullReferenceException to match expected failure case in workflows.")] 
                public override T Value 
                {
                    get 
                    {
                        // Only allow access to public properties, EXCEPT that Locations are top-level variables
                        // from the other's perspective, not internal properties, so they're okay as a special case.
                        // E.g. "[N]" from the user's perspective is not accessing a nonpublic property, even though 
                        // at an implementation level it is.
                        MethodInfo getMethodInfo = this.propertyInfo.GetGetMethod(); 
                        if (getMethodInfo == null && !TypeHelper.AreTypesCompatible(this.propertyInfo.DeclaringType, typeof(Location))) 
                        {
                            throw FxTrace.Exception.AsError(new InvalidOperationException(SR.WriteonlyPropertyCannotBeRead(this.propertyInfo.DeclaringType, this.propertyInfo.Name))); 
                        }

                        if (this.owner == null && (getMethodInfo == null || !getMethodInfo.IsStatic))
                        { 
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.propertyInfo.Name)));
                        } 
 
                        // Okay, it's public
                        return (T)this.propertyInfo.GetValue(this.owner, null); 
                    }

                    set
                    { 
                        // Only allow access to public properties, EXCEPT that Locations are top-level variables
                        // from the other's perspective, not internal properties, so they're okay as a special case. 
                        // E.g. "[N]" from the user's perspective is not accessing a nonpublic property, even though 
                        // at an implementation level it is.
                        MethodInfo setMethodInfo = this.propertyInfo.GetSetMethod(); 
                        if (setMethodInfo == null && !TypeHelper.AreTypesCompatible(this.propertyInfo.DeclaringType, typeof(Location)))
                        {
                            throw FxTrace.Exception.AsError(new InvalidOperationException(SR.ReadonlyPropertyCannotBeSet(this.propertyInfo.DeclaringType, this.propertyInfo.Name)));
                        } 

                        if (this.owner == null && (setMethodInfo == null || !setMethodInfo.IsStatic)) 
                        { 
                            throw FxTrace.Exception.AsError(new NullReferenceException(SR.CannotDereferenceNull(this.propertyInfo.Name)));
                        } 

                        // Okay, it's public
                        this.propertyInfo.SetValue(this.owner, value, null);
                        if (this.parent != null) 
                        {
                            // Looks like we are trying to set a property on a struct 
                            // Calling SetValue simply sets the property on the local copy of the struct, which is not very helpful 
                            // Since we have a copy, assign it back to the parent
                            this.parent.Value = this.owner; 
                        }
                    }
                }
            } 
        }
 
        // Returns true if it changed the expression (newExpression != expression). 
        // If it returns false then newExpression is set equal to expression.
        // This method uses the metadata parameter to generate violations (workflow 
        // artifacts which are not visible) and to generate inline references
        // (references at a higher scope which can be resolved at runtime).
        public static bool TryRewriteLambdaExpression(Expression expression, out Expression newExpression, CodeActivityMetadata metadata)
        { 
            newExpression = expression;
 
            if (expression == null) 
            {
                return false; 
            }

            // Share some local declarations across the switch
            Expression left = null; 
            Expression right = null;
            Expression other = null; 
            bool hasChanged = false; 
            IList expressionList = null;
            IList initializerList = null; 
            IList bindingList = null;
            MethodCallExpression methodCall = null;
            BinaryExpression binaryExpression = null;
            NewArrayExpression newArray = null; 
            UnaryExpression unaryExpression = null;
 
            switch (expression.NodeType) 
            {
                case ExpressionType.Add: 
                case ExpressionType.AddChecked:
                case ExpressionType.And:
                case ExpressionType.AndAlso:
                case ExpressionType.Coalesce: 
                case ExpressionType.Divide:
                case ExpressionType.Equal: 
                case ExpressionType.ExclusiveOr: 
                case ExpressionType.GreaterThan:
                case ExpressionType.GreaterThanOrEqual: 
                case ExpressionType.LeftShift:
                case ExpressionType.LessThan:
                case ExpressionType.LessThanOrEqual:
                case ExpressionType.Modulo: 
                case ExpressionType.Multiply:
                case ExpressionType.MultiplyChecked: 
                case ExpressionType.NotEqual: 
                case ExpressionType.Or:
                case ExpressionType.OrElse: 
                case ExpressionType.Power:
                case ExpressionType.RightShift:
                case ExpressionType.Subtract:
                case ExpressionType.SubtractChecked: 
                    binaryExpression = (BinaryExpression)expression;
 
                    hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, metadata); 
                    hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, metadata);
                    hasChanged |= TryRewriteLambdaExpression(binaryExpression.Conversion, out other, metadata); 

                    if (hasChanged)
                    {
                        newExpression = Expression.MakeBinary( 
                            binaryExpression.NodeType,
                            left, 
                            right, 
                            binaryExpression.IsLiftedToNull,
                            binaryExpression.Method, 
                            (LambdaExpression)other);
                    }
                    break;
 
                case ExpressionType.Conditional:
                    ConditionalExpression conditional = (ConditionalExpression)expression; 
 
                    hasChanged |= TryRewriteLambdaExpression(conditional.Test, out other, metadata);
                    hasChanged |= TryRewriteLambdaExpression(conditional.IfTrue, out left, metadata); 
                    hasChanged |= TryRewriteLambdaExpression(conditional.IfFalse, out right, metadata);

                    if (hasChanged)
                    { 
                        newExpression = Expression.Condition(
                            other, 
                            left, 
                            right);
                    } 
                    break;

                case ExpressionType.Constant:
                    break; 

                case ExpressionType.Invoke: 
                    InvocationExpression invocation = (InvocationExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpression(invocation.Expression, out other, metadata); 
                    hasChanged |= TryRewriteLambdaExpressionCollection(invocation.Arguments, out expressionList, metadata);

                    if (hasChanged)
                    { 
                        newExpression = Expression.Invoke(
                            other, 
                            expressionList); 
                    }
                    break; 

                case ExpressionType.Lambda:
                    LambdaExpression lambda = (LambdaExpression)expression;
 
                    hasChanged |= TryRewriteLambdaExpression(lambda.Body, out other, metadata);
 
                    if (hasChanged) 
                    {
                        newExpression = Expression.Lambda( 
                            lambda.Type,
                            other,
                            lambda.Parameters);
                    } 
                    break;
 
                case ExpressionType.ListInit: 
                    ListInitExpression listInit = (ListInitExpression)expression;
 
                    hasChanged |= TryRewriteLambdaExpression(listInit.NewExpression, out other, metadata);
                    hasChanged |= TryRewriteLambdaExpressionInitializersCollection(listInit.Initializers, out initializerList, metadata);

                    if (hasChanged) 
                    {
                        newExpression = Expression.ListInit( 
                            (NewExpression)other, 
                            initializerList);
                    } 
                    break;

                case ExpressionType.Parameter:
                    break; 

                case ExpressionType.MemberAccess: 
                    MemberExpression memberExpression = (MemberExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpression(memberExpression.Expression, out other, metadata); 

                    if (hasChanged)
                    {
                        newExpression = Expression.MakeMemberAccess( 
                            other,
                            memberExpression.Member); 
                    } 
                    break;
 
                case ExpressionType.MemberInit:
                    MemberInitExpression memberInit = (MemberInitExpression)expression;

                    hasChanged |= TryRewriteLambdaExpression(memberInit.NewExpression, out other, metadata); 
                    hasChanged |= TryRewriteLambdaExpressionBindingsCollection(memberInit.Bindings, out bindingList, metadata);
 
                    if (hasChanged) 
                    {
                        newExpression = Expression.MemberInit( 
                            (NewExpression)other,
                            bindingList);
                    }
                    break; 

                case ExpressionType.ArrayIndex: 
                    // ArrayIndex can be a MethodCallExpression or a BinaryExpression 
                    methodCall = expression as MethodCallExpression;
                    if (methodCall != null) 
                    {
                        hasChanged |= TryRewriteLambdaExpression(methodCall.Object, out other, metadata);
                        hasChanged |= TryRewriteLambdaExpressionCollection(methodCall.Arguments, out expressionList, metadata);
 
                        if (hasChanged)
                        { 
                            newExpression = Expression.ArrayIndex( 
                                other,
                                expressionList); 
                        }
                    }
                    else
                    { 
                        binaryExpression = (BinaryExpression)expression;
 
                        hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, metadata); 
                        hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, metadata);
 
                        if (hasChanged)
                        {
                            newExpression = Expression.ArrayIndex(
                                left, 
                                right);
                        } 
                    } 
                    break;
 
                case ExpressionType.Call:
                    methodCall = (MethodCallExpression)expression;

                    // TryRewriteMethodCall does all the real work 
                    hasChanged = TryRewriteMethodCall(methodCall, out newExpression, metadata);
                    break; 
 
                case ExpressionType.NewArrayInit:
                    newArray = (NewArrayExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpressionCollection(newArray.Expressions, out expressionList, metadata);

                    if (hasChanged) 
                    {
                        newExpression = Expression.NewArrayInit( 
                            newArray.Type.GetElementType(), 
                            expressionList);
                    } 
                    break;

                case ExpressionType.NewArrayBounds:
                    newArray = (NewArrayExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpressionCollection(newArray.Expressions, out expressionList, metadata); 
 
                    if (hasChanged)
                    { 
                        newExpression = Expression.NewArrayBounds(
                            newArray.Type.GetElementType(),
                            expressionList);
                    } 
                    break;
 
                case ExpressionType.New: 
                    NewExpression objectCreationExpression = (NewExpression)expression;
 
                    if (objectCreationExpression.Constructor == null)
                    {
                        // must be creating a valuetype
                        Fx.Assert(objectCreationExpression.Arguments.Count == 0, "NewExpression with null Constructor but some arguments"); 
                    }
                    else 
                    { 
                        hasChanged |= TryRewriteLambdaExpressionCollection(objectCreationExpression.Arguments, out expressionList, metadata);
 
                        if (hasChanged)
                        {
                            newExpression = Expression.New(
                                objectCreationExpression.Constructor, 
                                expressionList);
                        } 
                    } 
                    break;
 
                case ExpressionType.TypeIs:
                    TypeBinaryExpression typeBinary = (TypeBinaryExpression)expression;

                    hasChanged |= TryRewriteLambdaExpression(typeBinary.Expression, out other, metadata); 

                    if (hasChanged) 
                    { 
                        newExpression = Expression.TypeIs(
                            other, 
                            typeBinary.TypeOperand);
                    }
                    break;
 
                case ExpressionType.ArrayLength:
                case ExpressionType.Convert: 
                case ExpressionType.ConvertChecked: 
                case ExpressionType.Negate:
                case ExpressionType.NegateChecked: 
                case ExpressionType.Not:
                case ExpressionType.Quote:
                case ExpressionType.TypeAs:
                    unaryExpression = (UnaryExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpression(unaryExpression.Operand, out left, metadata); 
 
                    if (hasChanged)
                    { 
                        newExpression = Expression.MakeUnary(
                            unaryExpression.NodeType,
                            left,
                            unaryExpression.Type, 
                            unaryExpression.Method);
                    } 
                    break; 

                case ExpressionType.UnaryPlus: 
                    unaryExpression = (UnaryExpression)expression;

                    hasChanged |= TryRewriteLambdaExpression(unaryExpression.Operand, out left, metadata);
 
                    if (hasChanged)
                    { 
                        newExpression = Expression.UnaryPlus( 
                            left,
                            unaryExpression.Method); 
                    }
                    break;

                // Expression Tree V2.0 types. This is due to the hosted VB compiler generating ET V2.0 nodes. 

                case ExpressionType.Block: 
                    BlockExpression block = (BlockExpression)expression; 

                    hasChanged |= TryRewriteLambdaExpressionCollection(block.Expressions, out expressionList, metadata); 

                    if (hasChanged)
                    {
                        // Parameter collections are never rewritten 
                        newExpression = Expression.Block(block.Variables, expressionList);
                    } 
                    break; 

                case ExpressionType.Assign: 
                    binaryExpression = (BinaryExpression)expression;

                    hasChanged |= TryRewriteLambdaExpression(binaryExpression.Left, out left, metadata);
                    hasChanged |= TryRewriteLambdaExpression(binaryExpression.Right, out right, metadata); 

                    if (hasChanged) 
                    { 
                        newExpression = Expression.Assign(left, right);
                    } 
                    break;
            }

            return hasChanged; 
        }
 
        static bool TryRewriteLambdaExpressionBindingsCollection(IList bindings, out IList newBindings, CodeActivityMetadata metadata) 
        {
            IList temporaryBindings = null; 

            for (int i = 0; i < bindings.Count; i++)
            {
                MemberBinding binding = bindings[i]; 

                MemberBinding newBinding; 
                if (TryRewriteMemberBinding(binding, out newBinding, metadata)) 
                {
                    if (temporaryBindings == null) 
                    {
                        // We initialize this list with the unchanged bindings
                        temporaryBindings = new List(bindings.Count);
 
                        for (int j = 0; j < i; j++)
                        { 
                            temporaryBindings.Add(bindings[j]); 
                        }
                    } 
                }

                // At this point newBinding is either the updated binding (if
                // rewrite returned true) or the original binding (if false 
                // was returned)
                if (temporaryBindings != null) 
                { 
                    temporaryBindings.Add(newBinding);
                } 
            }

            if (temporaryBindings != null)
            { 
                newBindings = temporaryBindings;
                return true; 
            } 
            else
            { 
                newBindings = bindings;
                return false;
            }
        } 

        static bool TryRewriteMemberBinding(MemberBinding binding, out MemberBinding newBinding, CodeActivityMetadata metadata) 
        { 
            newBinding = binding;
 
            bool hasChanged = false;
            Expression other = null;
            IList initializerList = null;
            IList bindingList = null; 

            switch (binding.BindingType) 
            { 
                case MemberBindingType.Assignment:
                    MemberAssignment assignment = (MemberAssignment)binding; 

                    hasChanged |= TryRewriteLambdaExpression(assignment.Expression, out other, metadata);

                    if (hasChanged) 
                    {
                        newBinding = Expression.Bind(assignment.Member, other); 
                    } 
                    break;
 
                case MemberBindingType.ListBinding:
                    MemberListBinding list = (MemberListBinding)binding;

                    hasChanged |= TryRewriteLambdaExpressionInitializersCollection(list.Initializers, out initializerList, metadata); 

                    if (hasChanged) 
                    { 
                        newBinding = Expression.ListBind(list.Member, initializerList);
                    } 
                    break;

                case MemberBindingType.MemberBinding:
                    MemberMemberBinding member = (MemberMemberBinding)binding; 

                    hasChanged |= TryRewriteLambdaExpressionBindingsCollection(member.Bindings, out bindingList, metadata); 
 
                    if (hasChanged)
                    { 
                        newBinding = Expression.MemberBind(member.Member, bindingList);
                    }
                    break;
            } 

            return hasChanged; 
        } 

 
        static bool TryRewriteLambdaExpressionCollection(IList expressions, out IList newExpressions, CodeActivityMetadata metadata)
        {
            IList temporaryExpressions = null;
 
            for (int i = 0; i < expressions.Count; i++)
            { 
                Expression expression = expressions[i]; 

                Expression newExpression; 
                if (TryRewriteLambdaExpression(expression, out newExpression, metadata))
                {
                    if (temporaryExpressions == null)
                    { 
                        // We initialize the list by copying all of the unchanged
                        // expressions over 
                        temporaryExpressions = new List(expressions.Count); 

                        for (int j = 0; j < i; j++) 
                        {
                            temporaryExpressions.Add(expressions[j]);
                        }
                    } 
                }
 
                // newExpression will either be set to the new expression (true was 
                // returned) or the original expression (false was returned)
                if (temporaryExpressions != null) 
                {
                    temporaryExpressions.Add(newExpression);
                }
            } 

            if (temporaryExpressions != null) 
            { 
                newExpressions = temporaryExpressions;
                return true; 
            }
            else
            {
                newExpressions = expressions; 
                return false;
            } 
        } 

        static bool TryRewriteLambdaExpressionInitializersCollection(IList initializers, out IList newInitializers, CodeActivityMetadata metadata) 
        {
            IList temporaryInitializers = null;

            for (int i = 0; i < initializers.Count; i++) 
            {
                ElementInit elementInit = initializers[i]; 
 
                IList newExpressions;
                if (TryRewriteLambdaExpressionCollection(elementInit.Arguments, out newExpressions, metadata)) 
                {
                    if (temporaryInitializers == null)
                    {
                        // We initialize the list by copying all of the unchanged 
                        // initializers over
                        temporaryInitializers = new List(initializers.Count); 
 
                        for (int j = 0; j < i; j++)
                        { 
                            temporaryInitializers.Add(initializers[j]);
                        }
                    }
 
                    elementInit = Expression.ElementInit(elementInit.AddMethod, newExpressions);
                } 
 
                if (temporaryInitializers != null)
                { 
                    temporaryInitializers.Add(elementInit);
                }
            }
 
            if (temporaryInitializers != null)
            { 
                newInitializers = temporaryInitializers; 
                return true;
            } 
            else
            {
                newInitializers = initializers;
                return false; 
            }
        } 
 
        static bool TryGetInlinedArgumentReference(MethodCallExpression originalExpression, Expression argumentExpression, out LocationReference inlinedReference, CodeActivityMetadata metadata)
        { 
            inlinedReference = null;

            Argument argument = null;
            object tempArgument; 

            if (CustomMemberResolver(argumentExpression, out tempArgument) && tempArgument is Argument) 
            { 
                argument = (Argument)tempArgument;
            } 
            else
            {
                try
                { 
                    Expression> argumentLambda = Expression.Lambda>(argumentExpression);
                    Func argumentFunc = argumentLambda.Compile(); 
                    argument = argumentFunc(); 
                }
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e))
                    {
                        throw; 
                    }
 
                    metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, e)); ; 
                    return false;
                } 
            }

            if (argument == null)
            { 
                if (argumentExpression.NodeType == ExpressionType.MemberAccess)
                { 
                    MemberExpression memberExpression = (MemberExpression)argumentExpression; 
                    if (memberExpression.Member.MemberType == MemberTypes.Property)
                    { 
                        RuntimeArgument runtimeArgument = ActivityUtilities.FindArgument(memberExpression.Member.Name, metadata.CurrentActivity);

                        if (runtimeArgument != null && metadata.TryGetInlinedLocationReference(runtimeArgument, out inlinedReference))
                        { 
                            return true;
                        } 
                    } 
                }
 
                metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, SR.SubexpressionResultWasNull(argumentExpression.Type)));
                return false;
            }
            else 
            {
                if (argument.RuntimeArgument == null || !metadata.TryGetInlinedLocationReference(argument.RuntimeArgument, out inlinedReference)) 
                { 
                    metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(argumentExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(argumentExpression.Type)));
                    return false; 
                }
                else
                {
                    return true; 
                }
            } 
        } 

        static bool TryRewriteArgumentGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata) 
        {
            // We verify that this is a method we are expecting (single parameter
            // of type ActivityContext).  If not, we won't rewrite it at all
            // and will just let it fail at runtime. 
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments;
 
            if (argumentExpressions.Count == 1) 
            {
                Expression contextExpression = argumentExpressions[0]; 

                if (contextExpression.Type == activityContextType)
                {
                    LocationReference inlinedReference; 
                    if (TryGetInlinedArgumentReference(originalExpression, originalExpression.Object, out inlinedReference, metadata))
                    { 
                        newExpression = Expression.Call(contextExpression, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference)); 
                        return true;
                    } 
                }
            }

            newExpression = originalExpression; 
            return false;
        } 
 
        static bool TryRewriteArgumentGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata)
        { 
            // We verify that this is a method we are expecting (single parameter
            // of type ActivityContext).  If not, we won't rewrite it at all
            // and will just let it fail at runtime.
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments; 

            if (argumentExpressions.Count == 1) 
            { 
                Expression contextExpression = argumentExpressions[0];
 
                if (contextExpression.Type == activityContextType)
                {
                    LocationReference inlinedReference;
                    if (TryGetInlinedArgumentReference(originalExpression, originalExpression.Object, out inlinedReference, metadata)) 
                    {
                        if (returnType == null) 
                        { 
                            newExpression = Expression.Call(Expression.Constant(inlinedReference), locationReferenceGetLocationMethod, contextExpression);
                        } 
                        else
                        {
                            newExpression = Expression.Call(contextExpression, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference));
                        } 

                        return true; 
                    } 
                }
            } 

            newExpression = originalExpression;
            return false;
        } 

        static bool TryRewriteLocationReferenceSubclassGetCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata) 
        { 
            // We verify that this is a method we are expecting (single parameter
            // of type ActivityContext).  If not, we won't rewrite it at all 
            // and will just let it fail at runtime.
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments;

            if (argumentExpressions.Count == 1) 
            {
                Expression contextExpression = argumentExpressions[0]; 
 
                if (contextExpression.Type == activityContextType)
                { 
                    LocationReference inlinedReference;
                    if (TryGetInlinedLocationReference(originalExpression, originalExpression.Object, out inlinedReference, metadata))
                    {
                        newExpression = Expression.Call(contextExpression, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference)); 
                        return true;
                    } 
                } 
            }
 
            newExpression = originalExpression;
            return false;
        }
 
        static bool TryRewriteLocationReferenceSubclassGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata)
        { 
            // We verify that this is a method we are expecting (single parameter 
            // of type ActivityContext).  If not, we won't rewrite it at all
            // and will just let it fail at runtime. 
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments;

            if (argumentExpressions.Count == 1)
            { 
                Expression contextExpression = argumentExpressions[0];
 
                if (contextExpression.Type == activityContextType) 
                {
                    LocationReference inlinedReference; 
                    if (TryGetInlinedLocationReference(originalExpression, originalExpression.Object, out inlinedReference, metadata))
                    {
                        if (returnType == null)
                        { 
                            newExpression = Expression.Call(Expression.Constant(inlinedReference), locationReferenceGetLocationMethod, originalExpression.Arguments[0]);
                        } 
                        else 
                        {
                            newExpression = Expression.Call(contextExpression, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference)); 
                        }

                        return true;
                    } 
                }
            } 
 
            newExpression = originalExpression;
            return false; 
        }

        static bool CustomMemberResolver(Expression expression, out object memberValue)
        { 
            memberValue = null;
 
            switch (expression.NodeType) 
            {
                case ExpressionType.Constant: 
                    ConstantExpression constantExpression = expression as ConstantExpression;
                    memberValue = constantExpression.Value;
                    // memberValue = null means:
                    // 1. The expression does not follow the common patterns(local, field or property) 
                    // which we optimize(do not compile using Linq compiler) and try to resolve directly in this method
                    // OR 2. The expression actually resolved to null. 
                    // In both these cases, we compile the expression and run it so that we have a single error path. 
                    return memberValue != null;
 
                case ExpressionType.MemberAccess:
                    MemberExpression memberExpression = expression as MemberExpression;
                    if (memberExpression.Expression != null)
                    { 
                        CustomMemberResolver(memberExpression.Expression, out memberValue);
                        memberValue = GetMemberValue(memberExpression.Member, memberValue); 
                    } 
                    return memberValue != null;
 
                default:
                    return false;
            }
        } 

        static object GetMemberValue(MemberInfo memberInfo, object owner) 
        { 
            if (owner == null)
            { 
                // We do not want to throw any exceptions here. We
                // will just do the regular compile in this case.
                return null;
            } 

            MemberTypes memberType = memberInfo.MemberType; 
            if (memberType == MemberTypes.Property) 
            {
                PropertyInfo propertyInfo = memberInfo as PropertyInfo; 
                return propertyInfo.GetValue(owner, null);

            }
            else if (memberType == MemberTypes.Field) 
            {
                FieldInfo fieldInfo = memberInfo as FieldInfo; 
                return fieldInfo.GetValue(owner); 
            }
            return null; 
        }

        static bool TryGetInlinedLocationReference(MethodCallExpression originalExpression, Expression locationReferenceExpression, out LocationReference inlinedReference, CodeActivityMetadata metadata)
        { 
            inlinedReference = null;
 
            LocationReference locationReference = null; 
            object tempLocationReference;
            if (CustomMemberResolver(locationReferenceExpression, out tempLocationReference) && tempLocationReference is LocationReference) 
            {
                locationReference = (LocationReference)tempLocationReference;
            }
            else 
            {
                try 
                { 
                    Expression> locationReferenceLambda = Expression.Lambda>(locationReferenceExpression);
                    Func locationReferenceFunc = locationReferenceLambda.Compile(); 
                    locationReference = locationReferenceFunc();
                }
                catch (Exception e)
                { 
                    if (Fx.IsFatal(e))
                    { 
                        throw; 
                    }
 
                    metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, e)); ;
                    return false;
                }
            } 

            if (locationReference == null) 
            { 
                metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, SR.SubexpressionResultWasNull(locationReferenceExpression.Type)));
                return false; 
            }
            else if (!metadata.TryGetInlinedLocationReference(locationReference, out inlinedReference))
            {
                metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(locationReferenceExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(locationReferenceExpression.Type))); 
                return false;
            } 
            else 
            {
                return true; 
            }
        }

        static bool TryRewriteActivityContextGetValueCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata) 
        {
            newExpression = originalExpression; 
 
            LocationReference inlinedReference = null;
 
            // We verify that this is a method we are expecting (single parameter
            // of either LocationReference or Argument type).  If not, we won't
            // rewrite it at all and will just let it fail at runtime.
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments; 

            if (argumentExpressions.Count == 1) 
            { 
                Expression parameterExpression = argumentExpressions[0];
 
                if (TypeHelper.AreTypesCompatible(parameterExpression.Type, typeof(Argument)))
                {
                    if (!TryGetInlinedArgumentReference(originalExpression, parameterExpression, out inlinedReference, metadata))
                    { 
                        metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(parameterExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(parameterExpression.Type)));
                        return false; 
                    } 
                }
                else if (TypeHelper.AreTypesCompatible(parameterExpression.Type, typeof(LocationReference))) 
                {
                    if (!TryGetInlinedLocationReference(originalExpression, parameterExpression, out inlinedReference, metadata))
                    {
                        metadata.AddValidationError(SR.ErrorExtractingValuesForLambdaRewrite(parameterExpression.Type, originalExpression, SR.SubexpressionResultWasNotVisible(parameterExpression.Type))); 
                        return false;
                    } 
                } 
            }
 
            if (inlinedReference != null)
            {
                newExpression = Expression.Call(originalExpression.Object, activityContextGetValueGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference));
                return true; 
            }
 
            return false; 
        }
 
        static bool TryRewriteActivityContextGetLocationCall(MethodCallExpression originalExpression, Type returnType, out Expression newExpression, CodeActivityMetadata metadata)
        {
            // We verify that this is a method we are expecting (single parameter
            // of LocationReference type).  If not, we won't rewrite it at all 
            // and will just let it fail at runtime.
            ReadOnlyCollection argumentExpressions = originalExpression.Arguments; 
 
            if (argumentExpressions.Count == 1)
            { 
                Expression locationReference = argumentExpressions[0];

                if (TypeHelper.AreTypesCompatible(locationReference.Type, locationReferenceType))
                { 
                    LocationReference inlinedReference;
                    if (TryGetInlinedLocationReference(originalExpression, originalExpression.Arguments[0], out inlinedReference, metadata)) 
                    { 
                        newExpression = Expression.Call(originalExpression.Object, activityContextGetLocationGenericMethod.MakeGenericMethod(returnType), Expression.Constant(inlinedReference));
                        return true; 
                    }
                }
            }
 
            newExpression = originalExpression;
            return false; 
        } 

        // Local perf testing leads to the following preference for matching method infos: 
        //   * object.ReferenceEquals(info1, info2) is the fastest
        //   * info1.Name == "MethodName" is a close second
        //   * object.ReferenceEquals(info1, type.GetMethod("MethodName")) is very slow by comparison
        //   * object.ReferenceEquals(info1, genericMethodDefinition.MakeGenericMethod(typeParameter)) is also very 
        //     slow by comparison
        static bool TryRewriteMethodCall(MethodCallExpression methodCall, out Expression newExpression, CodeActivityMetadata metadata) 
        { 
            // NOTE: Here's the set of method call conversions/rewrites that we are
            // performing.  The left hand side of the "=>" is the pattern that from 
            // the original expression using the following shorthand for instances of
            // types:
            //    ctx = ActivityContext
            //    inArg = InArgument 
            //    inOutArg = InOutArgument
            //    outArg = OutArgument 
            //    arg = Argument 
            //    runtimeArg = RuntimeArgument
            //    ref = LocationReference (and subclasses) 
            //
            // The right hand side of the "=>" shows the rewritten method call.  When
            // the same symbol shows up on both sides that means we will use the same
            // expression (IE - ref.Get(ctx) => ctx.GetValue(inline) means that the 
            // expression for ctx on the left side is the same expression we should use
            // on the right side). 
            // 
            // "inline" is used in the right hand side to signify the inlined location
            // reference.  Except where explicitly called out, this is the inlined 
            // version of the LocationReference (or subclass) from the left hand side.
            //
            // Finally, "(new)" signifies that the method we are looking for hides a
            // method with the same signature on one of the base classes. 
            //
            // ActivityContext 
            //    ctx.GetValue(inArg) => ctx.GetValue(inline)  inline = Inline(inArg.RuntimeArgument) 
            //    ctx.GetValue(inOutArg) => ctx.GetValue(inline)  inline = Inline(inOutArg.RuntimeArgument)
            //    ctx.GetValue(outArg) => ctx.GetValue(inline)  inline = Inline(outArg.RuntimeArgument) 
            //    ctx.GetValue(arg) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument)
            //    ctx.GetValue(runtimeArg) => ctx.GetValue(inline)
            //    ctx.GetValue(ref) => ctx.GetValue(inline)
            //    ctx.GetLocation(ref) => ctx.GetLocation(inline) 
            //
            // LocationReference 
            //    ref.GetLocation(ctx) => inline.GetLocation(ctx) 
            //
            // RuntimeArgument : LocationReference 
            //    ref.Get(ctx) => ctx.GetValue(inline)
            //    ref.Get(ctx) => ctx.GetValue(inline)
            //
            // Argument 
            //    arg.Get(ctx) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument)
            //    arg.Get(ctx) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument) 
            //    arg.GetLocation(ctx) => inline.GetLocation(ctx)  inline = Inline(arg.RuntimeArgument) 
            //
            // InArgument : Argument 
            //    (new)  arg.Get(ctx) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument)
            //
            // InOutArgument : Argument
            //    (new)  arg.Get(ctx) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument) 
            //    (new)  arg.GetLocation(ctx) => ctx.GetLocation(inline)  inline = Inline(arg.RuntimeArgument)
            // 
            // OutArgument : Argument 
            //    (new)  arg.Get(ctx) => ctx.GetValue(inline)  inline = Inline(arg.RuntimeArgument)
            //    (new)  arg.GetLocation(ctx) => ctx.GetLocation(inline)  inline = Inline(arg.RuntimeArgument) 
            //
            // Variable : LocationReference
            //    ref.Get(ctx) => ctx.GetValue(inline)
            // 
            // Variable : Variable
            //    (new)  ref.Get(ctx) => ctx.GetValue(inline) 
            //    (new)  ref.GetLocation(ctx) => ctx.GetLocation(inline) 
            //
            // DelegateArgument : LocationReference 
            //    ref.Get(ctx) => ctx.GetValue(inline)
            //
            // DelegateInArgument : DelegateArgument
            //    (new) ref.Get(ctx) => ctx.GetValue(inline) 
            //
            // DelegateOutArgument : DelegateArgument 
            //    (new) ref.Get(ctx) => ctx.GetValue(inline) 
            //    (new) ref.GetLocation(ctx) => ctx.GetLocation(inline)
 
            MethodInfo targetMethod = methodCall.Method;
            Type targetObjectType = targetMethod.DeclaringType;

            if (targetObjectType.IsGenericType) 
            {
                // All of these methods are non-generic methods (they don't introduce a new 
                // type parameter), but they do make use of the type parameter of the 
                // generic declaring type.  Because of that we can't do MethodInfo comparison
                // and fall back to string comparison. 
                Type targetObjectGenericType = targetObjectType.GetGenericTypeDefinition();

                if (targetObjectGenericType == variableGenericType)
                { 
                    if (targetMethod.Name == "Get")
                    { 
                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                    else if (targetMethod.Name == "GetLocation") 
                    {
                        return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata);
                    }
                } 
                else if (targetObjectGenericType == inArgumentGenericType)
                { 
                    if (targetMethod.Name == "Get") 
                    {
                        return TryRewriteArgumentGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                }
                else if (targetObjectGenericType == outArgumentGenericType || targetObjectGenericType == inOutArgumentGenericType)
                { 
                    if (targetMethod.Name == "Get")
                    { 
                        return TryRewriteArgumentGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                    else if (targetMethod.Name == "GetLocation") 
                    {
                        return TryRewriteArgumentGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata);
                    }
                } 
                else if (targetObjectGenericType == delegateInArgumentGenericType)
                { 
                    if (targetMethod.Name == "Get") 
                    {
                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                }
                else if (targetObjectGenericType == delegateOutArgumentGenericType)
                { 
                    if (targetMethod.Name == "Get")
                    { 
                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                    else if (targetMethod.Name == "GetLocation") 
                    {
                        return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, targetObjectType.GetGenericArguments()[0], out newExpression, metadata);
                    }
                } 
            }
            else 
            { 
                if (targetObjectType == variableType)
                { 
                    if (object.ReferenceEquals(targetMethod, variableGetMethod))
                    {
                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, TypeHelper.ObjectType, out newExpression, metadata);
                    } 
                }
                else if (targetObjectType == delegateArgumentType) 
                { 
                    if (object.ReferenceEquals(targetMethod, delegateArgumentGetMethod))
                    { 
                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, TypeHelper.ObjectType, out newExpression, metadata);
                    }
                }
                else if (targetObjectType == activityContextType) 
                {
                    // We use the string comparison for these two because 
                    // we have several overloads of GetValue (some generic, 
                    // some not) and GetLocation is a generic method
                    if (targetMethod.Name == "GetValue") 
                    {
                        Type returnType = TypeHelper.ObjectType;

                        if (targetMethod.IsGenericMethod) 
                        {
                            returnType = targetMethod.GetGenericArguments()[0]; 
                        } 

                        return TryRewriteActivityContextGetValueCall(methodCall, returnType, out newExpression, metadata); 
                    }
                    else if (targetMethod.IsGenericMethod && targetMethod.Name == "GetLocation")
                    {
                        return TryRewriteActivityContextGetLocationCall(methodCall, targetMethod.GetGenericArguments()[0], out newExpression, metadata); 
                    }
                } 
                else if (targetObjectType == locationReferenceType) 
                {
                    if (object.ReferenceEquals(targetMethod, locationReferenceGetLocationMethod)) 
                    {
                        return TryRewriteLocationReferenceSubclassGetLocationCall(methodCall, null, out newExpression, metadata);
                    }
                } 
                else if (targetObjectType == runtimeArgumentType)
                { 
                    // We use string comparison here because we can 
                    // match both overloads with a single check.
                    if (targetMethod.Name == "Get") 
                    {
                        Type returnType = TypeHelper.ObjectType;

                        if (targetMethod.IsGenericMethod) 
                        {
                            returnType = targetMethod.GetGenericArguments()[0]; 
                        } 

                        return TryRewriteLocationReferenceSubclassGetCall(methodCall, returnType, out newExpression, metadata); 
                    }
                }
                else if (targetObjectType == argumentType)
                { 
                    // We use string comparison here because we can
                    // match both overloads with a single check. 
                    if (targetMethod.Name == "Get") 
                    {
                        Type returnType = TypeHelper.ObjectType; 

                        if (targetMethod.IsGenericMethod)
                        {
                            returnType = targetMethod.GetGenericArguments()[0]; 
                        }
 
                        return TryRewriteArgumentGetCall(methodCall, returnType, out newExpression, metadata); 
                    }
                    else if (object.ReferenceEquals(targetMethod, argumentGetLocationMethod)) 
                    {
                        return TryRewriteArgumentGetLocationCall(methodCall, null, out newExpression, metadata);
                    }
                } 
            }
 
            // Here's the code for a method call that isn't on our "special" list 
            newExpression = methodCall;
 
            Expression objectExpression;
            IList expressionList;

            bool hasChanged = TryRewriteLambdaExpression(methodCall.Object, out objectExpression, metadata); 
            hasChanged |= TryRewriteLambdaExpressionCollection(methodCall.Arguments, out expressionList, metadata);
 
            if (hasChanged) 
            {
                newExpression = Expression.Call(objectExpression, targetMethod, expressionList); 
            }

            return hasChanged;
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.


                        

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK