RuleValidation.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / Activities / Rules / RuleValidation.cs / 1305376 / RuleValidation.cs

                            // ---------------------------------------------------------------------------- 
// Copyright (C) 2006 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------

#define CODE_ANALYSIS 
using System.CodeDom;
using System.Collections.Generic; 
using System.Configuration; 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; 
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Workflow.ComponentModel; 
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities.Common; 
 
namespace System.Workflow.Activities.Rules
{ 
    #region ExpressionInfo

    // Public base class (which just holds the Type of the expression).
    public class RuleExpressionInfo 
    {
        private Type expressionType; 
 
        public RuleExpressionInfo(Type expressionType)
        { 
            this.expressionType = expressionType;
        }

        public Type ExpressionType 
        {
            get { return expressionType; } 
        } 
    }
 
    // Internal derivation for CodeMethodInvokeExpression
    internal class RuleMethodInvokeExpressionInfo : RuleExpressionInfo
    {
        private MethodInfo methodInfo; 
        private bool needsParamsExpansion;
 
        internal RuleMethodInvokeExpressionInfo(MethodInfo mi, bool needsParamsExpansion) 
            : base(mi.ReturnType)
        { 
            this.methodInfo = mi;
            this.needsParamsExpansion = needsParamsExpansion;
        }
 
        internal MethodInfo MethodInfo
        { 
            get { return methodInfo; } 
        }
 
        internal bool NeedsParamsExpansion
        {
            get { return needsParamsExpansion; }
        } 
    }
 
    // Internal derivation for CodeBinaryExpression 
    internal class RuleBinaryExpressionInfo : RuleExpressionInfo
    { 
        private Type leftType;
        private Type rightType;
        private MethodInfo methodInfo;
 
        // no overridden method needed
        internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, Type resultType) 
            : base(resultType) 
        {
            this.leftType = lhsType; 
            this.rightType = rhsType;
        }

        // overridden method found 
        internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, MethodInfo mi)
            : base(mi.ReturnType) 
        { 
            this.leftType = lhsType;
            this.rightType = rhsType; 
            this.methodInfo = mi;
        }

        internal Type LeftType 
        {
            get { return leftType; } 
        } 

        internal Type RightType 
        {
            get { return rightType; }
        }
 
        internal MethodInfo MethodInfo
        { 
            get { return methodInfo; } 
        }
    } 

    // Internal derivation for CodeFieldReferenceExpression
    internal class RuleFieldExpressionInfo : RuleExpressionInfo
    { 
        private FieldInfo fieldInfo;
 
        internal RuleFieldExpressionInfo(FieldInfo fi) 
            : base(fi.FieldType)
        { 
            fieldInfo = fi;
        }

        internal FieldInfo FieldInfo 
        {
            get { return fieldInfo; } 
        } 
    }
 
    // Internal derivation for CodePropertyReferenceExpression
    internal class RulePropertyExpressionInfo : RuleExpressionInfo
    {
        private PropertyInfo propertyInfo; 
        private bool needsParamsExpansion;
 
        // Note that the type pi.PropertyType may differ from the "exprType" argument if this 
        // property is a Bind.
        internal RulePropertyExpressionInfo(PropertyInfo pi, Type exprType, bool needsParamsExpansion) 
            : base(exprType)
        {
            this.propertyInfo = pi;
            this.needsParamsExpansion = needsParamsExpansion; 
        }
 
        internal PropertyInfo PropertyInfo 
        {
            get { return propertyInfo; } 
        }

        internal bool NeedsParamsExpansion
        { 
            get { return needsParamsExpansion; }
        } 
    } 

    // Internal derivation for CodeMethodInvokeExpression 
    internal class RuleConstructorExpressionInfo : RuleExpressionInfo
    {
        private ConstructorInfo constructorInfo;
        private bool needsParamsExpansion; 

        internal RuleConstructorExpressionInfo(ConstructorInfo ci, bool needsParamsExpansion) 
            : base(ci.DeclaringType) 
        {
            this.constructorInfo = ci; 
            this.needsParamsExpansion = needsParamsExpansion;
        }

        internal ConstructorInfo ConstructorInfo 
        {
            get { return constructorInfo; } 
        } 

        internal bool NeedsParamsExpansion 
        {
            get { return needsParamsExpansion; }
        }
    } 

    internal class ExtensionMethodInfo : MethodInfo 
    { 
        MethodInfo actualMethod;
        int actualParameterLength; 
        ParameterInfo[] expectedParameters;
        Type assumedDeclaringType;
        bool hasOutOrRefParameters = false;
 
        public ExtensionMethodInfo(MethodInfo method, ParameterInfo[] actualParameters)
            : base() 
        { 
            Debug.Assert(method.IsStatic, "Expected static method as an extension method");
 
            actualMethod = method;
            // modify parameters
            actualParameterLength = actualParameters.Length;
            if (actualParameterLength < 2) 
                expectedParameters = new ParameterInfo[0];
            else 
            { 
                expectedParameters = new ParameterInfo[actualParameterLength - 1];
                Array.Copy(actualParameters, 1, expectedParameters, 0, actualParameterLength - 1); 
                foreach (ParameterInfo pi in expectedParameters)
                {
                    if (pi.ParameterType.IsByRef)
                        hasOutOrRefParameters = true; 
                }
            } 
            // get the type we pretend this method is on (which happens to be the first actual parameter) 
            assumedDeclaringType = actualParameters[0].ParameterType;
        } 

        public override MethodInfo GetBaseDefinition()
        {
            return actualMethod.GetBaseDefinition(); 
        }
 
        public override ICustomAttributeProvider ReturnTypeCustomAttributes 
        {
            get { return actualMethod.ReturnTypeCustomAttributes; } 
        }

        public override MethodAttributes Attributes
        { 
            get { return actualMethod.Attributes & ~MethodAttributes.Static; }
        } 
 
        public override MethodImplAttributes GetMethodImplementationFlags()
        { 
            return actualMethod.GetMethodImplementationFlags();
        }

        public override ParameterInfo[] GetParameters() 
        {
            return expectedParameters; 
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        {
            object[] actualParameters = new object[actualParameterLength];
            if (actualParameterLength > 1)
                Array.Copy(parameters, 0, actualParameters, 1, actualParameterLength - 1); 
            if (obj == null)
                actualParameters[0] = null; 
            else 
                actualParameters[0] = Executor.AdjustType(obj.GetType(), obj, assumedDeclaringType);
            object result = actualMethod.Invoke(null, invokeAttr, binder, actualParameters, culture); 
            // may be out/ref parameters, so copy back the results
            if (hasOutOrRefParameters)
                Array.Copy(actualParameters, 1, parameters, 0, actualParameterLength - 1);
            return result; 
        }
 
        public override RuntimeMethodHandle MethodHandle 
        {
            get { return actualMethod.MethodHandle; } 
        }

        public override Type DeclaringType
        { 
            get { return actualMethod.DeclaringType; }
        } 
 
        public Type AssumedDeclaringType
        { 
            get { return assumedDeclaringType; }
        }

        public override object[] GetCustomAttributes(Type attributeType, bool inherit) 
        {
            return actualMethod.GetCustomAttributes(attributeType, inherit); 
        } 

        public override object[] GetCustomAttributes(bool inherit) 
        {
            return actualMethod.GetCustomAttributes(inherit);
        }
 
        public override bool IsDefined(Type attributeType, bool inherit)
        { 
            return actualMethod.IsDefined(attributeType, inherit); 
        }
 
        public override string Name
        {
            get { return actualMethod.Name; }
        } 

        public override Type ReflectedType 
        { 
            get { return actualMethod.ReflectedType; }
        } 

        public override Type ReturnType
        {
            get { return actualMethod.ReturnType; } 
        }
    } 
 
    internal class SimpleParameterInfo : ParameterInfo
    { 
        // only thing we look at is ParameterType, so no need to override anything else
        Type parameterType;

        public SimpleParameterInfo(ParameterInfo parameter) 
            : base()
        { 
            parameterType = typeof(Nullable<>).MakeGenericType(parameter.ParameterType); 
        }
 
        public SimpleParameterInfo(Type parameter)
            : base()
        {
            parameterType = parameter; 
        }
 
        public override Type ParameterType 
        {
            get 
            {
                return parameterType;
            }
        } 
    }
 
    internal abstract class BaseMethodInfo : MethodInfo 
    {
        protected MethodInfo actualMethod; 
        protected ParameterInfo[] expectedParameters;
        protected Type resultType;

        public BaseMethodInfo(MethodInfo method) 
            : base()
        { 
            Debug.Assert(method.IsStatic, "Expected static method as an lifted method"); 
            actualMethod = method;
            resultType = method.ReturnType; 
            expectedParameters = method.GetParameters();
        }

        public override MethodInfo GetBaseDefinition() 
        {
            return actualMethod.GetBaseDefinition(); 
        } 

        public override ICustomAttributeProvider ReturnTypeCustomAttributes 
        {
            get { return actualMethod.ReturnTypeCustomAttributes; }
        }
 
        public override MethodAttributes Attributes
        { 
            get { return actualMethod.Attributes & ~MethodAttributes.Static; } 
        }
 
        public override MethodImplAttributes GetMethodImplementationFlags()
        {
            return actualMethod.GetMethodImplementationFlags();
        } 

        public override ParameterInfo[] GetParameters() 
        { 
            return expectedParameters;
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        {
            throw new NotImplementedException(); 
        }
 
        public override RuntimeMethodHandle MethodHandle 
        {
            get { return actualMethod.MethodHandle; } 
        }

        public override Type DeclaringType
        { 
            get { return actualMethod.DeclaringType; }
        } 
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit)
        { 
            return actualMethod.GetCustomAttributes(attributeType, inherit);
        }

        public override object[] GetCustomAttributes(bool inherit) 
        {
            return actualMethod.GetCustomAttributes(inherit); 
        } 

        public override bool IsDefined(Type attributeType, bool inherit) 
        {
            return actualMethod.IsDefined(attributeType, inherit);
        }
 
        public override string Name
        { 
            get { return actualMethod.Name; } 
        }
 
        public override Type ReflectedType
        {
            get { return actualMethod.ReflectedType; }
        } 

        public override Type ReturnType 
        { 
            get { return resultType; }
        } 

        public override bool Equals(object obj)
        {
            BaseMethodInfo other = obj as BaseMethodInfo; 
            if ((other == null)
                || (actualMethod != other.actualMethod) 
                || (resultType != other.resultType) 
                || (expectedParameters.Length != other.expectedParameters.Length))
                return false; 
            for (int i = 0; i < expectedParameters.Length; ++i)
                if (expectedParameters[i].ParameterType != other.expectedParameters[i].ParameterType)
                    return false;
            return true; 
        }
 
        public override int GetHashCode() 
        {
            int result = actualMethod.GetHashCode() ^ resultType.GetHashCode(); 
            for (int i = 0; i < expectedParameters.Length; ++i)
                result ^= expectedParameters[i].GetHashCode();
            return result;
        } 
    }
 
    internal class LiftedConversionMethodInfo : BaseMethodInfo 
    {
        public LiftedConversionMethodInfo(MethodInfo method) 
            : base(method)
        {
            Debug.Assert(expectedParameters.Length == 1, "not 1 parameters");
 
            // modify result
            resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType); 
 
            // modify parameter (exactly 1)
            ParameterInfo[] actualParameters = method.GetParameters(); 
            expectedParameters = new ParameterInfo[1];
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
        }
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null in, then result is null 
            if (parameters[0] == null)
                return Activator.CreateInstance(resultType); 

            // invoke the conversion from S -> T
            object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
            // return a T? 
            return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
        } 
    } 

    internal class LiftedArithmeticOperatorMethodInfo : BaseMethodInfo 
    {
        public LiftedArithmeticOperatorMethodInfo(MethodInfo method)
            : base(method)
        { 
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");
 
            // modify parameters (exactly 2, both need to be lifted) 
            ParameterInfo[] actualParameters = method.GetParameters();
            expectedParameters = new ParameterInfo[2]; 
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);

            // modify result 
            resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType);
        } 
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null in, then result is null
            if (parameters[0] == null)
                return null;
            if (parameters[1] == null) 
                return null;
 
            // apply the underlying operator 
            object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
            // return a T? 
            return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
        }
    }
 
    internal class LiftedEqualityOperatorMethodInfo : BaseMethodInfo
    { 
        public LiftedEqualityOperatorMethodInfo(MethodInfo method) 
            : base(method)
        { 
            Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");

            // modify parameters (exactly 2, both need to be lifted) 
            ParameterInfo[] actualParameters = method.GetParameters();
            expectedParameters = new ParameterInfo[2]; 
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]); 
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
 
            // set the result type
            resultType = typeof(bool);
        }
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null == null is true, null == something else is false, else call method 
            if (parameters[0] == null)
                return (parameters[1] == null); 
            else if (parameters[1] == null)
                return false;

            // invoke the actual comparison (parameters are unwrapped) 
            return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
        } 
    } 

    internal class LiftedRelationalOperatorMethodInfo : BaseMethodInfo 
    {
        public LiftedRelationalOperatorMethodInfo(MethodInfo method)
            : base(method)
        { 
            Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters"); 
 
            // modify parameters (exactly 2, both need to be lifted)
            ParameterInfo[] actualParameters = method.GetParameters(); 
            expectedParameters = new ParameterInfo[2];
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
 
            // set the result type
            resultType = typeof(bool); 
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        {
            // if either parameter is null, then result is false
            if (parameters[0] == null)
                return false; 
            if (parameters[1] == null)
                return false; 
 
            // invoke the actual comparison (parameters are unwrapped)
            return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture); 
        }
    }

    internal class EnumOperationMethodInfo : MethodInfo 
    {
        CodeBinaryOperatorType op; 
        ParameterInfo[] expectedParameters; 
        Type resultType;        // may be nullable, enum, or value type
        bool resultIsNullable;  // true if resultType is nullable 

        Type lhsBaseType;       // non-Nullable, may be enum
        Type rhsBaseType;
        Type resultBaseType; 

        Type lhsRootType;       // underlying type (int, long, ushort, etc) 
        Type rhsRootType; 
        Type resultRootType;
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        public EnumOperationMethodInfo(Type lhs, CodeBinaryOperatorType operation, Type rhs, bool isZero)
        {
            // only 5 arithmetic cases (U = underlying type of E): 
            //    E = E + U
            //    E = U + E 
            //    U = E - E 
            //    E = E - U
            //    E = U - E 
            // plus 5 comparison cases
            //    E == E
            //    E < E
            //    E <= E 
            //    E > E
            //    E >= E 
            // either E can be nullable 

            op = operation; 

            // parameters are easy -- they are the same as the type passed in
            expectedParameters = new ParameterInfo[2];
            expectedParameters[0] = new SimpleParameterInfo(lhs); 
            expectedParameters[1] = new SimpleParameterInfo(rhs);
 
            // compute return type (depends on type of operation) 
            // start by getting the types without Nullable<>
            bool lhsNullable = ConditionHelper.IsNullableValueType(lhs); 
            bool rhsNullable = ConditionHelper.IsNullableValueType(rhs);
            lhsBaseType = (lhsNullable) ? Nullable.GetUnderlyingType(lhs) : lhs;
            rhsBaseType = (rhsNullable) ? Nullable.GetUnderlyingType(rhs) : rhs;
            // determine the underlying types for both sides 
            if (lhsBaseType.IsEnum)
                lhsRootType = EnumHelper.GetUnderlyingType(lhsBaseType); 
            else 
                lhsRootType = lhsBaseType;
 
            if (rhsBaseType.IsEnum)
                rhsRootType = EnumHelper.GetUnderlyingType(rhsBaseType);
            else
                rhsRootType = rhsBaseType; 

            switch (op) 
            { 
                case CodeBinaryOperatorType.Add:
                    // add always produces an enum, except enum + enum 
                    if ((lhsBaseType.IsEnum) && (rhs.IsEnum))
                        resultBaseType = lhsRootType;
                    else if (lhsBaseType.IsEnum)
                        resultBaseType = lhsBaseType; 
                    else
                        resultBaseType = rhsBaseType; 
                    // if either side is nullable, result is nullable 
                    resultIsNullable = (lhsNullable || rhsNullable);
                    resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType; 
                    break;
                case CodeBinaryOperatorType.Subtract:
                    // subtract can be an enum or the underlying type
                    if (rhsBaseType.IsEnum && lhsBaseType.IsEnum) 
                    {
                        resultRootType = rhsRootType; 
                        resultBaseType = rhsRootType; 
                    }
                    else if (lhsBaseType.IsEnum) 
                    {
                        // special case for E - 0
                        // if 0 is the underlying type, then use E - U
                        // if not the underlying type, then 0 becomes E, use E - E 
                        resultRootType = lhsRootType;
                        if (isZero && rhsBaseType != lhsRootType) 
                            resultBaseType = lhsRootType; 
                        else
                            resultBaseType = lhsBaseType; 
                    }
                    else    // rhsType.IsEnum
                    {
                        // special case for 0 - E 
                        // in all cases 0 becomes E, use E - E
                        resultRootType = rhsRootType; 
                        if (isZero) 
                            resultBaseType = rhsRootType;
                        else 
                            resultBaseType = rhsBaseType;
                    }
                    resultIsNullable = (lhsNullable || rhsNullable);
                    resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType; 
                    break;
                case CodeBinaryOperatorType.ValueEquality: 
                case CodeBinaryOperatorType.LessThan: 
                case CodeBinaryOperatorType.LessThanOrEqual:
                case CodeBinaryOperatorType.GreaterThan: 
                case CodeBinaryOperatorType.GreaterThanOrEqual:
                    resultType = typeof(bool);
                    break;
            } 
        }
 
        public override MethodInfo GetBaseDefinition() 
        {
            return null; 
        }

        public override ICustomAttributeProvider ReturnTypeCustomAttributes
        { 
            get { return null; }
        } 
 
        public override MethodAttributes Attributes
        { 
            get { return MethodAttributes.Static; }
        }

        public override MethodImplAttributes GetMethodImplementationFlags() 
        {
            return MethodImplAttributes.Runtime; 
        } 

        public override ParameterInfo[] GetParameters() 
        {
            return expectedParameters;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        { 
            // we should get passed in 2 values that correspond to the parameter types
 
            object result;
            ArithmeticLiteral leftArithmetic, rightArithmetic;
            Literal leftLiteral, rightLiteral;
 
            // for design-time types we couldn't find the underlying type, so do it now
            if (lhsRootType == null) 
                lhsRootType = Enum.GetUnderlyingType(lhsBaseType); 
            if (rhsRootType == null)
                rhsRootType = Enum.GetUnderlyingType(rhsBaseType); 

            switch (op)
            {
                case CodeBinaryOperatorType.Add: 
                    // if either is null, then the result is null
                    if ((parameters[0] == null) || (parameters[1] == null)) 
                        return null; 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsRootType, parameters[0]);
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsRootType, parameters[1]); 
                    result = leftArithmetic.Add(rightArithmetic);
                    result = Executor.AdjustType(result.GetType(), result, resultBaseType);
                    if (resultIsNullable)
                        result = Activator.CreateInstance(resultType, result); 
                    return result;
                case CodeBinaryOperatorType.Subtract: 
                    // if either is null, then the result is null 
                    if ((parameters[0] == null) || (parameters[1] == null))
                        return null; 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
                        Executor.AdjustType(lhsRootType, parameters[0], resultRootType));
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
                        Executor.AdjustType(rhsRootType, parameters[1], resultRootType)); 
                    result = leftArithmetic.Subtract(rightArithmetic);
                    result = Executor.AdjustType(result.GetType(), result, resultBaseType); 
                    if (resultIsNullable) 
                        result = Activator.CreateInstance(resultType, result);
                    return result; 

                case CodeBinaryOperatorType.ValueEquality:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]); 
                    return leftLiteral.Equal(rightLiteral);
                case CodeBinaryOperatorType.LessThan: 
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]); 
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.LessThan(rightLiteral); 
                case CodeBinaryOperatorType.LessThanOrEqual:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.LessThanOrEqual(rightLiteral); 
                case CodeBinaryOperatorType.GreaterThan:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]); 
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]); 
                    return leftLiteral.GreaterThan(rightLiteral);
                case CodeBinaryOperatorType.GreaterThanOrEqual: 
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.GreaterThanOrEqual(rightLiteral);
            } 
            string message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, op.ToString());
            throw new RuleEvaluationException(message); 
        } 

        public override RuntimeMethodHandle MethodHandle 
        {
            get { return new RuntimeMethodHandle(); }
        }
 
        public override Type DeclaringType
        { 
            get { return typeof(Enum); } 
        }
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit)
        {
            return new object[0];
        } 

        public override object[] GetCustomAttributes(bool inherit) 
        { 
            return new object[0];
        } 

        public override bool IsDefined(Type attributeType, bool inherit)
        {
            return true; 
        }
 
        public override string Name 
        {
            get { return "op_Enum"; } 
        }

        public override Type ReflectedType
        { 
            get { return resultType; }
        } 
 
        public override Type ReturnType
        { 
            get { return resultType; }
        }
    }
    #endregion 

    #region SimpleRunTimeTypeProvider 
 
    internal class SimpleRunTimeTypeProvider : ITypeProvider
    { 
        private Assembly root;
        private List references;

        internal SimpleRunTimeTypeProvider(Assembly startingAssembly) 
        {
            root = startingAssembly; 
        } 

        public Type GetType(string name) 
        {
            return GetType(name, false);
        }
 
        public Type GetType(string name, bool throwOnError)
        { 
            // is the type available in the main workflow assembly? 
            Type type = root.GetType(name, throwOnError, false);
            if (type != null) 
                return type;

            // now try mscorlib or this assembly
            // (or if the name is an assembly qualified name) 
            type = Type.GetType(name, throwOnError, false);
            if (type != null) 
                return type; 

            // no luck so far, so try all referenced assemblies 
            foreach (Assembly a in ReferencedAssemblies)
            {
                type = a.GetType(name, throwOnError, false);
                if (type != null) 
                    return type;
            } 
 
            // keep going by trying all loaded assemblies
            Assembly[] loaded = AppDomain.CurrentDomain.GetAssemblies(); 
            for (int i = 0; i < loaded.Length; ++i)
            {
                type = loaded[i].GetType(name, throwOnError, false);
                if (type != null) 
                    return type;
            } 
            return null; 
        }
 
        public Type[] GetTypes()
        {
            List types = new List();
            try 
            {
                types.AddRange(root.GetTypes()); 
            } 
            catch (ReflectionTypeLoadException e)
            { 
                // problems loading all the types, take what we can get
                foreach (Type type in e.Types)
                    if (type != null)
                        types.Add(type); 
            }
            foreach (Assembly a in ReferencedAssemblies) 
            { 
                try
                { 
                    types.AddRange(a.GetTypes());
                }
                catch (ReflectionTypeLoadException e)
                { 
                    // problems loading all the types, take what we can get
                    foreach (Type type in e.Types) 
                        if (type != null) 
                            types.Add(type);
                } 
            }
            return types.ToArray();
        }
 
        public Assembly LocalAssembly
        { 
            get { return root; } 
        }
 
        public ICollection ReferencedAssemblies
        {
            get
            { 
                // references is created on demand, does not include root
                if (references == null) 
                { 
                    List list = new List();
                    foreach (AssemblyName a in root.GetReferencedAssemblies()) 
                    {
                        list.Add(Assembly.Load(a));
                    }
                    references = list; 
                }
                return references; 
            } 
        }
 
        public IDictionary TypeLoadErrors
        {
            get
            { 
                // we never use this method, so add use of EventHandlers to keep compiler happy
                TypesChanged.Invoke(this, null); 
                TypeLoadErrorsChanged.Invoke(this, null); 
                return null;
            } 
        }

        public event EventHandler TypesChanged;
 
        public event EventHandler TypeLoadErrorsChanged;
    } 
    #endregion 

    #region RuleValidation 

    public class RuleValidation
    {
        private Type thisType; 
        private ITypeProvider typeProvider;
        private ValidationErrorCollection errors = new ValidationErrorCollection(); 
        private Dictionary typesUsed = new Dictionary(16); 
        private Dictionary typesUsedAuthorized;
        private Stack activeParentNodes = new Stack(); 
        private Dictionary expressionInfoMap = new Dictionary();
        private Dictionary typeRefMap = new Dictionary();
        private bool checkStaticType;
        private IList authorizedTypes; 
        private static readonly Type voidType = typeof(void);
        private static string voidTypeName = voidType.AssemblyQualifiedName; 
 
        #region Constructors
 
        // Validate at design time.
        public RuleValidation(Activity activity, ITypeProvider typeProvider, bool checkStaticType)
        {
            if (activity == null) 
                throw new ArgumentNullException("activity");
            if (typeProvider == null) 
                throw new ArgumentNullException("typeProvider"); 

            this.thisType = ConditionHelper.GetContextType(typeProvider, activity); 
            this.typeProvider = typeProvider;
            this.checkStaticType = checkStaticType;
            if (checkStaticType)
            { 
                Debug.Assert(WorkflowCompilationContext.Current != null, "Can't have checkTypes set to true without a context in scope");
                this.authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes(); 
                this.typesUsedAuthorized = new Dictionary(); 
                this.typesUsedAuthorized.Add(voidTypeName, voidType);
            } 
        }

        // Validate at runtime when we have the actual subject instance.  This is
        // mostly for conditions used in activities like IfElse. 
        internal RuleValidation(object thisObject)
        { 
            if (thisObject == null) 
                throw new ArgumentNullException("thisObject");
 
            this.thisType = thisObject.GetType();
            this.typeProvider = new SimpleRunTimeTypeProvider(this.thisType.Assembly);
        }
 
        // Validate at runtime when we have just the type.  This is mostly for rules.
        public RuleValidation(Type thisType, ITypeProvider typeProvider) 
        { 
            if (thisType == null)
                throw new ArgumentNullException("thisType"); 

            this.thisType = thisType;
            this.typeProvider = (typeProvider != null) ? typeProvider : new SimpleRunTimeTypeProvider(this.thisType.Assembly);
        } 

        #endregion 
 
        #region Internal validation methods
 
        internal bool ValidateConditionExpression(CodeExpression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression"); 

            // Run the validation pass. 
            RuleExpressionInfo exprInfo = RuleExpressionWalker.Validate(this, expression, false); 
            if (exprInfo == null)
                return false; 

            Type resultType = exprInfo.ExpressionType;
            if (!IsValidBooleanResult(resultType))
            { 
                // not a boolean, so complain unless another error may have caused this problem
                if (resultType != null || Errors.Count == 0) 
                { 
                    string message = Messages.ConditionMustBeBoolean;
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_ConditionMustBeBoolean); 
                    error.UserData[RuleUserDataKeys.ErrorObject] = expression;
                    Errors.Add(error);
                }
            } 

            return Errors.Count == 0; 
        } 

        internal static bool IsValidBooleanResult(Type type) 
        {
            return ((type == typeof(bool))
                || (type == typeof(bool?))
                || (ImplicitConversion(type, typeof(bool)))); 
        }
 
        internal static bool IsPrivate(MethodInfo methodInfo) 
        {
            return methodInfo.IsPrivate 
                || methodInfo.IsFamily
                || methodInfo.IsFamilyOrAssembly
                || methodInfo.IsFamilyAndAssembly;
        } 

        internal static bool IsPrivate(FieldInfo fieldInfo) 
        { 
            return fieldInfo.IsPrivate
                || fieldInfo.IsFamily 
                || fieldInfo.IsFamilyOrAssembly
                || fieldInfo.IsFamilyAndAssembly;
        }
 
        internal static bool IsInternal(MethodInfo methodInfo)
        { 
            return methodInfo.IsAssembly 
                || methodInfo.IsFamilyAndAssembly;
        } 

        internal static bool IsInternal(FieldInfo fieldInfo)
        {
            return fieldInfo.IsAssembly 
                || fieldInfo.IsFamilyAndAssembly;
        } 
 
        #endregion
 
        #region Miscellaneous public properties & methods

        public Type ThisType
        { 
            get { return thisType; }
        } 
 
        internal ITypeProvider GetTypeProvider()
        { 
            return typeProvider;
        }

        public ValidationErrorCollection Errors 
        {
            get { return errors; } 
        } 

        internal bool AllowInternalMembers(Type type) 
        {
            return type.Assembly == thisType.Assembly;
        }
 
        internal void AddError(ValidationError error)
        { 
            this.Errors.Add(error); 
        }
 
        public bool PushParentExpression(CodeExpression newParent)
        {
            if (newParent == null)
                throw new ArgumentNullException("newParent"); 

            if (activeParentNodes.Contains(newParent)) 
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CyclicalExpression);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CyclicalExpression); 
                error.UserData[RuleUserDataKeys.ErrorObject] = newParent;
                Errors.Add(error);
                return false;
            } 

            activeParentNodes.Push(newParent); 
            return true; 
        }
 
        public void PopParentExpression()
        {
            activeParentNodes.Pop();
        } 

        // Get the ExpressionInfo associated with a given CodeExpression 
        public RuleExpressionInfo ExpressionInfo(CodeExpression expression) 
        {
            if (expression == null) 
                throw new ArgumentNullException("expression");

            RuleExpressionInfo exprInfo = null;
            expressionInfoMap.TryGetValue(expression, out exprInfo); 

            return exprInfo; 
        } 

        #endregion 

        #region CodeDom Expression Validation methods

        internal RuleExpressionInfo ValidateSubexpression(CodeExpression expr, RuleExpressionInternal ruleExpr, bool isWritten) 
        {
            Debug.Assert(ruleExpr != null, "Validation::ValidateSubexpression - IRuleExpression is null"); 
            Debug.Assert(expr != null, "Validation::ValidateSubexpression - CodeExpression is null"); 

            RuleExpressionInfo exprInfo = ruleExpr.Validate(expr, this, isWritten); 

            if (exprInfo != null)
            {
                // Add the CodeExpression object to the info map.  We don't want to add the IRuleExpression guy 
                // as the key, since it might likely be just a tearoff wrapper.
                expressionInfoMap[expr] = exprInfo; 
            } 

            return exprInfo; 
        }

        internal static bool TypesAreAssignable(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)
        { 
            // determine if rhsType can be implicitly converted to lhsType,
            // following the rules in C# specification section 6.1, 
            // plus support for Nullable 

            // all but 6.1.7 handled as a standard implicit conversion 
            if (StandardImplicitConversion(rhsType, lhsType, rhsExpression, out error))
                return true;
            if (error != null)
                return false; 

            // no standard implicit conversion works, see if user specified one 
            // from section 6.4.3, start by determining what types to check 
            // as we find each type, add the list of implicit conversions available
            if (FindImplicitConversion(rhsType, lhsType, out error) == null) 
                return false;
            return true;
        }
 
        internal static bool ExplicitConversionSpecified(Type fromType, Type toType, out ValidationError error)
        { 
            // determine if fromType can be implicitly converted to toType, 
            // following the rules in C# specification section 6.2
 
            // start by seeing if there is a standard implicit conversion
            if (StandardImplicitConversion(fromType, toType, null, out error))
                return true;
            if (error != null) 
                return false;
 
            // explicit numeric conversions 
            // also handles Enum conversions, since GetTypeCode returns the underlying type
            if (fromType.IsValueType && toType.IsValueType && IsExplicitNumericConversion(fromType, toType)) 
                return true;

            // explicit reference conversions
            // this looks like the inverse of implicit conversions 
            ValidationError dummyError;		// so we don't return an error
            if (StandardImplicitConversion(toType, fromType, null, out dummyError)) 
                return true; 
            // include interface checks
            if (toType.IsInterface) 
            {
                // from any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
                // latter part should be handled by implicit conversion, so we are ok as long as class is not sealed
                if ((fromType.IsClass) && (!fromType.IsSealed)) 
                    return true;
                // from any interface-type S to any interface-type T, provided S is not derived from T. 
                // again, if S derived from T, handled by implicit conversion above 
                if (fromType.IsInterface)
                    return true; 
            }
            if (fromType.IsInterface)
            {
                // from any interface-type S to any class-type T, provided T is not sealed or provided T implements S. 
                if ((toType.IsClass) && ((!toType.IsSealed) || (InterfaceMatch(toType.GetInterfaces(), fromType))))
                    return true; 
            } 

            // no look for user-defined conversions 
            // from section 6.4.4, start by determining what types to check
            // as we find each type, add the list of implicit conversions available
            if (FindExplicitConversion(fromType, toType, out error) == null)
                return false; 
            return true;
        } 
 
        private static bool InterfaceMatch(Type[] types, Type fromType)
        { 
            foreach (Type t in types)
            {
                if (t == fromType)
                    return true; 
            }
            return false; 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        internal static MethodInfo FindImplicitConversion(Type fromType, Type toType, out ValidationError error)
        {
            List candidates = new List();
 
            bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
            bool toIsNullable = ConditionHelper.IsNullableValueType(toType); 
            Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType; 
            Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
 
            if (fromType0.IsClass)
            {
                AddImplicitConversions(fromType0, fromType, toType, candidates);
                Type baseType = fromType0.BaseType; 
                while ((baseType != null) && (baseType != typeof(object)))
                { 
                    AddImplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                } 
            }
            else if (IsStruct(fromType0))
            {
                AddImplicitConversions(fromType0, fromType, toType, candidates); 
            }
            if ((toType0.IsClass) || (IsStruct(toType0))) 
            { 
                AddImplicitConversions(toType0, fromType, toType, candidates);
            } 

            // if both types are nullable, add the lifted operators
            if (fromIsNullable && toIsNullable)
            { 
                // start by finding all the conversion operators from S0 -> T0
                List liftedCandidates = new List(); 
                if (fromType0.IsClass) 
                {
                    AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates); 
                    Type baseType = fromType0.BaseType;
                    while ((baseType != null) && (baseType != typeof(object)))
                    {
                        AddImplicitConversions(baseType, fromType0, toType0, liftedCandidates); 
                        baseType = baseType.BaseType;
                    } 
                } 
                else if (IsStruct(fromType0))
                { 
                    AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
                }
                if ((toType0.IsClass) || (IsStruct(toType0)))
                { 
                    AddImplicitConversions(toType0, fromType0, toType0, liftedCandidates);
                } 
 
                // add them all to the candidates list as lifted methods (which wraps them appropriately)
                foreach (MethodInfo mi in liftedCandidates) 
                {
                    // only lift candidates that convert from a non-nullable value type
                    // to a non-nullable value type
                    ParameterInfo[] parameters = mi.GetParameters(); 
                    if (ConditionHelper.IsNonNullableValueType(mi.ReturnType) && ConditionHelper.IsNonNullableValueType(parameters[0].ParameterType))
                        candidates.Add(new LiftedConversionMethodInfo(mi)); 
                } 
            }
 
            if (candidates.Count == 0)
            {
                // no overrides, so must be false
                string message = string.Format(CultureInfo.CurrentCulture, 
                    Messages.NoConversion,
                    RuleDecompiler.DecompileType(fromType), 
                    RuleDecompiler.DecompileType(toType)); 
                error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                return null; 
            }

            // find the most specific source type
            ValidationError dummyError;		// so we don't return an error 
            Type sx = candidates[0].GetParameters()[0].ParameterType;
            if (sx != fromType) 
            { 
                for (int i = 1; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (testType == fromType)
                    {
                        // we have a match with the source type, so that's the correct answer 
                        sx = fromType;
                        break; 
                    } 
                    if (StandardImplicitConversion(testType, sx, null, out dummyError))
                        sx = testType; 
                }
            }

            // find the most specific target type 
            Type tx = candidates[0].ReturnType;
            if (tx != toType) 
            { 
                for (int i = 1; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].ReturnType;
                    if (testType == toType)
                    {
                        // we have a match with the target type, so that's the correct answer 
                        tx = toType;
                        break; 
                    } 
                    if (StandardImplicitConversion(tx, testType, null, out dummyError))
                        tx = testType; 
                }
            }

            // see how many candidates convert from sx to tx, ignoring lifted methods 
            int numMatches = 0;
            int position = 0; 
            for (int i = 0; i < candidates.Count; ++i) 
            {
                if ((candidates[i].ReturnType == tx) && 
                    (candidates[i].GetParameters()[0].ParameterType == sx) &&
                    (!(candidates[i] is LiftedConversionMethodInfo)))
                {
                    position = i; 
                    ++numMatches;
                } 
            } 
            if (numMatches == 1)
            { 
                // found what we are looking for
                error = null;
                return candidates[position];
            } 

            // now check for lifted conversions 
            if ((toIsNullable) && (numMatches == 0)) 
            {
                if (fromIsNullable) 
                {
                    for (int i = 0; i < candidates.Count; ++i)
                    {
                        if ((candidates[i].ReturnType == tx) && 
                            (candidates[i].GetParameters()[0].ParameterType == sx) &&
                            (candidates[i] is LiftedConversionMethodInfo)) 
                        { 
                            position = i;
                            ++numMatches; 
                        }
                    }
                    if (numMatches == 1)
                    { 
                        // found what we are looking for
                        error = null; 
                        return candidates[position]; 
                    }
                } 
                else
                {
                    // we are doing a conversion T? = S, so a conversion from S -> T is valid
                    MethodInfo result = FindImplicitConversion(fromType, toType0, out error); 
                    if (result != null)
                    { 
                        error = null; 
                        // return it as a lifted method so the wrapping to T? is done
                        return new LiftedConversionMethodInfo(result); 
                    }
                }
            }
 
            // no exact matches, so it's an error
            string message2 = string.Format(CultureInfo.CurrentCulture, 
                Messages.AmbiguousConversion, 
                RuleDecompiler.DecompileType(fromType),
                RuleDecompiler.DecompileType(toType)); 
            error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible);
            return null;
        }
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal static MethodInfo FindExplicitConversion(Type fromType, Type toType, out ValidationError error) 
        { 
            List candidates = new List();
            ValidationError dummyError;		// don't return transient errors 

            bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
            bool toIsNullable = ConditionHelper.IsNullableValueType(toType);
            Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType; 
            Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
 
            if (fromType0.IsClass) 
            {
                AddExplicitConversions(fromType0, fromType, toType, candidates); 
                Type baseType = fromType0.BaseType;
                while ((baseType != null) && (baseType != typeof(object)))
                {
                    AddExplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                } 
            } 
            else if (IsStruct(fromType0))
            { 
                AddExplicitConversions(fromType0, fromType, toType, candidates);
            }
            if (toType0.IsClass)
            { 
                AddExplicitConversions(toType0, fromType, toType, candidates);
                Type baseType = toType0.BaseType; 
                while ((baseType != null) && (baseType != typeof(object))) 
                {
                    AddExplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                }
            }
            else if (IsStruct(toType0)) 
            {
                AddExplicitConversions(toType0, fromType, toType, candidates); 
            } 

            // if both types are nullable, add the lifted operators 
            if (fromIsNullable && toIsNullable)
            {
                // start by finding all the conversion operators from S0 -> T0
                List liftedCandidates = new List(); 
                if (fromType0.IsClass)
                { 
                    AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates); 
                    Type baseType = fromType0.BaseType;
                    while ((baseType != null) && (baseType != typeof(object))) 
                    {
                        AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates);
                        baseType = baseType.BaseType;
                    } 
                }
                else if (IsStruct(fromType0)) 
                { 
                    AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
                } 
                if (toType0.IsClass)
                {
                    AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates);
                    Type baseType = toType0.BaseType; 
                    while ((baseType != null) && (baseType != typeof(object)))
                    { 
                        AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates); 
                        baseType = baseType.BaseType;
                    } 
                }
                else if (IsStruct(toType0))
                {
                    AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates); 
                }
 
                // add them all to the candidates list as lifted methods (which wraps them appropriately) 
                foreach (MethodInfo mi in liftedCandidates)
                    candidates.Add(new LiftedConversionMethodInfo(mi)); 
            }

            if (candidates.Count == 0)
            { 
                // no overrides, so must be false
                string message = string.Format(CultureInfo.CurrentCulture, 
                    Messages.NoConversion, 
                    RuleDecompiler.DecompileType(fromType),
                    RuleDecompiler.DecompileType(toType)); 
                error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                return null;
            }
 
            // find the most specific source type
            // if any are s, s is the answer 
            Type sx = null; 
            for (int i = 0; i < candidates.Count; ++i)
            { 
                Type testType = candidates[i].GetParameters()[0].ParameterType;
                if (testType == fromType)
                {
                    // we have a match with the source type, so that's the correct answer 
                    sx = fromType;
                    break; 
                } 
            }
            // if no match, find the most encompassed type if the type encompasses s 
            if (sx == null)
            {
                for (int i = 0; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (StandardImplicitConversion(fromType, testType, null, out dummyError)) 
                    { 
                        if (sx == null)
                            sx = testType; 
                        else if (StandardImplicitConversion(testType, sx, null, out dummyError))
                            sx = testType;
                    }
                } 
            }
            // still no match, find most encompassing type 
            if (sx == null) 
            {
                for (int i = 0; i < candidates.Count; ++i) 
                {
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (StandardImplicitConversion(testType, fromType, null, out dummyError))
                    { 
                        if (sx == null)
                            sx = testType; 
                        else if (StandardImplicitConversion(sx, testType, null, out dummyError)) 
                            sx = testType;
                    } 
                }
            }

            // find the most specific target type 
            // if any are t, t is the answer
            Type tx = null; 
            for (int i = 0; i < candidates.Count; ++i) 
            {
                Type testType = candidates[i].ReturnType; 
                if (testType == toType)
                {
                    // we have a match with the target type, so that's the correct answer
                    tx = toType; 
                    break;
                } 
            } 
            // if no match, find the most encompassed type if the type encompasses s
            if (tx == null) 
            {
                for (int i = 0; i < candidates.Count; ++i)
                {
                    Type testType = candidates[i].ReturnType; 
                    if (StandardImplicitConversion(testType, toType, null, out dummyError))
                    { 
                        if (tx == null) 
                            tx = testType;
                        else if (StandardImplicitConversion(tx, testType, null, out dummyError)) 
                            tx = testType;
                    }
                }
            } 
            // still no match, find most encompassing type
            if (tx == null) 
            { 
                for (int i = 0; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].ReturnType;
                    if (StandardImplicitConversion(toType, testType, null, out dummyError))
                    {
                        if (tx == null) 
                            tx = testType;
                        else if (StandardImplicitConversion(testType, tx, null, out dummyError)) 
                            tx = testType; 
                    }
                } 
            }

            // see how many candidates convert from sx to tx, ignoring lifted methods
            int numMatches = 0; 
            int position = 0;
            for (int i = 0; i < candidates.Count; ++i) 
            { 
                if ((candidates[i].ReturnType == tx) &&
                        (candidates[i].GetParameters()[0].ParameterType == sx) && 
                        (!(candidates[i] is LiftedConversionMethodInfo)))
                {
                    position = i;
                    ++numMatches; 
                }
            } 
            if (numMatches == 1) 
            {
                // found what we are looking for 
                error = null;
                return candidates[position];
            }
 
            // now check for lifted conversions
            if ((toIsNullable) && (numMatches == 0)) 
            { 
                if (fromIsNullable)
                { 
                    for (int i = 0; i < candidates.Count; ++i)
                    {
                        if ((candidates[i].ReturnType == tx) &&
                            (candidates[i].GetParameters()[0].ParameterType == sx) && 
                            (candidates[i] is LiftedConversionMethodInfo))
                        { 
                            position = i; 
                            ++numMatches;
                        } 
                    }
                    if (numMatches == 1)
                    {
                        // found what we are looking for 
                        error = null;
                        return candidates[position]; 
                    } 
                }
                else 
                {
                    // we are doing a conversion T? = S, so a conversion from S -> T is valid
                    MethodInfo result = FindExplicitConversion(fromType, toType0, out error);
                    if (result != null) 
                    {
                        error = null; 
                        // return it as a lifted method so the wrapping to T? is done 
                        return new LiftedConversionMethodInfo(result);
                    } 
                }
            }

            // no exact matches, so it's an error 
            string message2 = string.Format(CultureInfo.CurrentCulture,
                Messages.AmbiguousConversion, 
                RuleDecompiler.DecompileType(fromType), 
                RuleDecompiler.DecompileType(toType));
            error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible); 
            return null;
        }

        private static bool IsStruct(Type type) 
        {
            return ((type.IsValueType) && (!type.IsPrimitive)); 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        private static bool IsExplicitNumericConversion(Type sourceType, Type testType)
        {
            // includes the implicit conversions as well
 
            // unwrap nullables
            TypeCode sourceTypeCode = (ConditionHelper.IsNullableValueType(sourceType)) 
                ? Type.GetTypeCode(sourceType.GetGenericArguments()[0]) 
                : Type.GetTypeCode(sourceType);
            TypeCode testTypeCode = (ConditionHelper.IsNullableValueType(testType)) 
                ? Type.GetTypeCode(testType.GetGenericArguments()[0])
                : Type.GetTypeCode(testType);

            switch (sourceTypeCode) 
            {
                case TypeCode.SByte: 
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.UInt16:
                        case TypeCode.UInt32:
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
 
                        case TypeCode.Int16: 
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true; 
                    }
                    return false; 
 
                case TypeCode.Byte:
                    switch (testTypeCode) 
                    {
                        case TypeCode.Byte:
                        case TypeCode.SByte:
                        case TypeCode.Char: 

                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    } 
                    return false;
 
                case TypeCode.Int16:
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.UInt16: 
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64:
                        case TypeCode.Char: 

                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false;

                case TypeCode.UInt16:
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Char:

                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    }
                    return false;
 
                case TypeCode.Int32:
                    switch (testTypeCode) 
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
 
                        case TypeCode.Int64:
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    } 
                    return false;
 
                case TypeCode.UInt32: 
                    switch (testTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Char: 

                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false; 

                case TypeCode.Int64: 
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Char:

                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true; 
                    }
                    return false; 

                case TypeCode.UInt64:
                    switch (testTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 

                        case TypeCode.Single: 
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    }
                    return false;

                case TypeCode.Char: 
                    switch (testTypeCode)
                    { 
                        case TypeCode.Char: 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:

                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64: 
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true;
                    }
                    return false; 

                case TypeCode.Single: 
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                        case TypeCode.Single: 
                        case TypeCode.Decimal:

                        case TypeCode.Double:
                            return true; 
                    }
                    return false; 
 
                case TypeCode.Double:
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false; 

                case TypeCode.Decimal: 
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Char:
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    } 
                    return false;
            } 
            return false;
        }

 
        internal static bool ImplicitConversion(Type fromType, Type toType)
        { 
            ValidationError error; 

            // is there a standard conversion we can use 
            if (StandardImplicitConversion(fromType, toType, null, out error))
                return true;

            // no standard one, did the user provide one? 
            return (FindImplicitConversion(fromType, toType, out error) != null);
        } 
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal static bool StandardImplicitConversion(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error) 
        {
            error = null;

            // 6.1.1 identity conversion 
            if (rhsType == lhsType)
            { 
                // Easy special case... they're the same type. 
                return true;
            } 

            // 6.1.4 (h) from the null type to any reference-type
            if (rhsType == typeof(NullLiteral))
            { 
                // Special case if the RHS is 'null'; just make sure the LHS type can be assigned a null value.
                if (ConditionHelper.IsNonNullableValueType(lhsType)) 
                { 
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.AssignNotAllowed, Messages.NullValue, RuleDecompiler.DecompileType(lhsType));
                    error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); 
                    return false;
                }
                return true;
            } 

            // check for nullables 
            bool lhsIsNullable = ConditionHelper.IsNullableValueType(lhsType); 
            bool rhsIsNullable = ConditionHelper.IsNullableValueType(rhsType);
            if (rhsIsNullable) 
            {
                if (!lhsIsNullable)
                {
                    // We had T1 = T2?, which is not valid for any T1 or T2, unless T1 is object 
                    return (lhsType == typeof(object));
                } 
 
                rhsType = Nullable.GetUnderlyingType(rhsType);
            } 

            if (lhsIsNullable)
                lhsType = Nullable.GetUnderlyingType(lhsType);
 
            if (lhsType == rhsType)
            { 
                // We had T? = T, which is valid. 
                return true;
            } 

            // handle rest of 6.1.4
            if (TypeProvider.IsAssignable(lhsType, rhsType))
            { 
                // They are assignable, which will handle inheritance and trivial up-casting.
                return true; 
            } 

            // 6.1.3 implicit enumeration conversions 
            if (lhsType.IsEnum)
            {
                // right-hand side can be decimal-integer-literal 0
                CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression; 
                if ((primitive == null) || (primitive.Value == null))
                { 
                    // not a constant 
                    return false;
                } 
                switch (Type.GetTypeCode(primitive.Value.GetType()))
                {
                    case TypeCode.SByte:
                        return ((sbyte)primitive.Value == 0); 
                    case TypeCode.Byte:
                        return ((byte)primitive.Value == 0); 
                    case TypeCode.Int16: 
                        return ((short)primitive.Value == 0);
                    case TypeCode.UInt16: 
                        return ((ushort)primitive.Value == 0);
                    case TypeCode.Int32:
                        return ((int)primitive.Value == 0);
                    case TypeCode.UInt32: 
                        return ((uint)primitive.Value == 0);
                    case TypeCode.Int64: 
                        return ((long)primitive.Value == 0); 
                    case TypeCode.UInt64:
                        return ((ulong)primitive.Value == 0); 
                    case TypeCode.Char:
                        return ((char)primitive.Value == 0);
                }
                return false; 
            }
            if (rhsType.IsEnum) 
            { 
                // don't treat enums as numbers
                return false; 
            }

            // 6.1.2 implicit numeric conversions
            // 6.1.6 implicit constant expression conversions 
            // not assignable, but the assignment might still be valid for
            // value types if a free conversion is available. 
            TypeCode lhsTypeCode = Type.GetTypeCode(lhsType); 
            TypeCode rhsTypeCode = Type.GetTypeCode(rhsType);
 
            switch (lhsTypeCode)
            {
                case TypeCode.Decimal:
                    switch (rhsTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Decimal:
                        case TypeCode.Char: 
                            return true; 
                    }
                    return false; 

                case TypeCode.Double:
                    switch (rhsTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Char: 
                            return true; 
                    }
                    return false; 

                case TypeCode.Single:
                    switch (rhsTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single: 
                        case TypeCode.Char:
                            return true; 
                    } 
                    return false;
 
                case TypeCode.Char:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.SByte:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                            return true;
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Byte:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int16:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                            return true; 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int32:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int64:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.Char:
                            return true;
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt16:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.Char: 
                            return true; 
                        case TypeCode.SByte:
                        case TypeCode.Int16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt32:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.UInt32: 
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt64:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                            return true; 
                        case TypeCode.SByte:
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                default:
                    // It wasn't a numeric type, it was some other kind of value type (e.g., bool,
                    // DateTime, etc).  There will be no conversions.
                    return false; 
            }
        } 
 
        private static void AddImplicitConversions(Type t, Type source, Type target, List methods)
        { 
            // append the list of methods that match the name specified
            // s is the source type, so the parameter must encompass it
            // t is the target type, so it must encompass the result
            MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public); 
            foreach (MethodInfo mi in possible)
            { 
                if ((mi.Name == "op_Implicit") && (mi.GetParameters().Length == 1)) 
                {
                    Type sourceType = mi.GetParameters()[0].ParameterType; 
                    Type targetType = mi.ReturnType;
                    ValidationError error;
                    if (StandardImplicitConversion(source, sourceType, null, out error) &&
                        StandardImplicitConversion(targetType, target, null, out error)) 
                    {
                        if (!methods.Contains(mi)) 
                            methods.Add(mi); 
                    }
                } 
            }
        }

        private static void AddExplicitConversions(Type t, Type source, Type target, List methods) 
        {
            // append the list of methods that match the name specified 
            // s is the source type, so the parameter must encompass it 
            // t is the target type, so it must encompass the result
            MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public); 
            foreach (MethodInfo mi in possible)
            {
                if (((mi.Name == "op_Implicit") || (mi.Name == "op_Explicit")) && (mi.GetParameters().Length == 1))
                { 
                    Type sourceType = mi.GetParameters()[0].ParameterType;
                    Type targetType = mi.ReturnType; 
                    ValidationError error; 
                    if ((StandardImplicitConversion(source, sourceType, null, out error) || StandardImplicitConversion(sourceType, source, null, out error))
                     && (StandardImplicitConversion(target, targetType, null, out error) || StandardImplicitConversion(targetType, target, null, out error))) 
                    {
                        if (!methods.Contains(mi))
                            methods.Add(mi);
                    } 
                }
            } 
        } 

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private static bool CheckValueRange(CodeExpression rhsExpression, Type lhsType, out ValidationError error)
        {
            error = null;
 
            CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression;
            if (primitive != null) 
            { 
                try
                { 
                    System.Convert.ChangeType(primitive.Value, lhsType, CultureInfo.CurrentCulture);
                    // If we get here without throwing, it's valid.
                    return true;
                } 
                catch (Exception e)
                { 
                    error = new ValidationError(e.Message, ErrorNumbers.Error_OperandTypesIncompatible); 
                    return false;
                } 
            }

            return false;
        } 

        internal bool ValidateMemberAccess( 
            CodeExpression targetExpression, Type targetType, FieldInfo accessorMethod, string memberName, CodeExpression parentExpr) 
        {
            return this.ValidateMemberAccess( 
                targetExpression, targetType, memberName, parentExpr,
                accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
        }
 
        internal bool ValidateMemberAccess(
            CodeExpression targetExpression, Type targetType, MethodInfo accessorMethod, string memberName, CodeExpression parentExpr) 
        { 
            return this.ValidateMemberAccess(
                targetExpression, targetType, memberName, parentExpr, 
                accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
        }

        private bool ValidateMemberAccess( 
            CodeExpression targetExpression, Type targetType, string memberName, CodeExpression parentExpr,
            Assembly methodAssembly, bool isPrivate, bool isInternal, bool isStatic) 
        { 
            string message;
 
            if (isStatic != (targetExpression is CodeTypeReferenceExpression))
            {
                // If it's static, then the target object must be a type ref, and vice versa.
 
                int errorNumber;
 
                if (isStatic) 
                {
                    // We have "object.StaticMember" 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.StaticMember, memberName);
                    errorNumber = ErrorNumbers.Error_StaticMember;
                }
                else 
                {
                    // We have "TypeName.NonStaticMember" 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.NonStaticMember, memberName); 
                    errorNumber = ErrorNumbers.Error_NonStaticMember;
                } 

                ValidationError error = new ValidationError(message, errorNumber);
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
                Errors.Add(error); 

                return false; 
            } 

            if (isPrivate && targetType != ThisType) 
            {
                // Can't access private members except on the subject type.
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessPrivateMember, memberName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
                Errors.Add(error); 
 
                return false;
            } 

            if (isInternal && ThisType.Assembly != methodAssembly)
            {
                // Can't access internal members except on the subject assembly. 
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessInternalMember, memberName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr; 
                Errors.Add(error);
 
                return false;
            }

            return true; 
        }
 
        #region Field and property resolution 

        internal MemberInfo ResolveFieldOrProperty(Type targetType, string name) 
        {
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
            if (AllowInternalMembers(targetType))
                bindingFlags |= BindingFlags.NonPublic; 

            // Look up a field or property of the given name. 
            MemberInfo[] results = targetType.GetMember(name, MemberTypes.Field | MemberTypes.Property, bindingFlags); 

            if (results != null) 
            {
                int numResults = results.Length;
                if (numResults == 1)
                { 
                    // If we found exactly one, we're good.
                    return results[0]; 
                } 
                else if (numResults > 1)
                { 
                    // We may have found more than one property if it's overloaded.  If we find one without
                    // any parameters, return that one.
                    for (int i = 0; i < numResults; ++i)
                    { 
                        MemberInfo member = results[i];
                        System.Diagnostics.Debug.Assert(member.MemberType == MemberTypes.Property, "only properties can be overloaded"); 
 
                        PropertyInfo pi = (PropertyInfo)member;
                        ParameterInfo[] parms = pi.GetIndexParameters(); 
                        if (parms == null || parms.Length == 0)
                        {
                            if (pi != null)
                            { 
                                IsAuthorized(pi.PropertyType);
                            } 
                            return pi; 
                        }
                    } 
                }
            }

            // If we didn't find it, and if the target type is an interface, try resolving a property 
            // that may exist in its inheritance chain.  (Fields cannot appear on interfaces.)
            if (targetType.IsInterface) 
                return ResolveProperty(targetType, name, bindingFlags); 

            // Otherwise, it's no good. 
            return null;
        }

        internal PropertyInfo ResolveProperty(Type targetType, string propertyName, BindingFlags bindingFlags) 
        {
 
            PropertyInfo pi = GetProperty(targetType, propertyName, bindingFlags); 
            if (pi == null && targetType.IsInterface)
            { 
                Type[] parentInterfacesArray = targetType.GetInterfaces();
                List parentInterfaces = new List();
                parentInterfaces.AddRange(parentInterfacesArray);
 
                int index = 0;
                while (index < parentInterfaces.Count) 
                { 
                    pi = GetProperty(parentInterfaces[index], propertyName, bindingFlags);
                    if (pi != null) 
                        break;

                    Type[] pInterfaces = parentInterfaces[index].GetInterfaces();
                    if (pInterfaces.Length > 0) 
                        parentInterfaces.AddRange(pInterfaces);
                    ++index; 
                } 
            }
 
            if (pi != null)
            {
                IsAuthorized(pi.PropertyType);
            } 
            return pi;
        } 
 
        private static PropertyInfo GetProperty(Type targetType, string propertyName, BindingFlags bindingFlags)
        { 
            // Properties may be overloaded (in VB), so we have to ---- out those that we can support,
            // i.e., those that have no parameters.

            MemberInfo[] members = targetType.GetMember(propertyName, MemberTypes.Property, bindingFlags); 
            for (int m = 0; m < members.Length; ++m)
            { 
                PropertyInfo pi = (PropertyInfo)members[m]; 

                ParameterInfo[] parms = pi.GetIndexParameters(); 
                if (parms == null || parms.Length == 0)
                    return pi;
            }
 
            return null;
        } 
 
        #endregion
 
        #region Method resolution

        private class Argument
        { 
            internal CodeExpression expression;
            internal FieldDirection direction; 
            internal Type type; 

            internal Argument(CodeExpression expr, RuleValidation validation) 
            {
                this.expression = expr;

                this.direction = FieldDirection.In; 
                CodeDirectionExpression directionExpr = expr as CodeDirectionExpression;
                if (directionExpr != null) 
                    this.direction = directionExpr.Direction; 

                this.type = validation.ExpressionInfo(expr).ExpressionType; 
            }

            internal Argument(Type type)
            { 
                this.direction = FieldDirection.In;
                this.type = type; 
            } 
        }
 
        private class CandidateParameter
        {
            private Type type;
            private FieldDirection direction; 

            internal CandidateParameter(Type type) 
            { 
                this.type = type;
                this.direction = FieldDirection.In; 
            }

            internal CandidateParameter(ParameterInfo paramInfo)
            { 
                this.direction = FieldDirection.In;
                if (paramInfo.IsOut) 
                    this.direction = FieldDirection.Out; 
                else if (paramInfo.ParameterType.IsByRef)
                    this.direction = FieldDirection.Ref; 

                this.type = paramInfo.ParameterType;
            }
 
            internal bool Match(Argument argument, string methodName, int argPosition, out ValidationError error)
            { 
                string message; 

                // If we don't agree on the argument direction, this method is not a candidate. 
                if (this.direction != argument.direction)
                {
                    string dirString = "";
                    switch (this.direction) 
                    {
                        case FieldDirection.In: 
                            dirString = "in"; // No localization required, this is a keyword. 
                            break;
                        case FieldDirection.Out: 
                            dirString = "out"; // No localization required, this is a keyword.
                            break;
                        case FieldDirection.Ref:
                            dirString = "ref"; // No localization required, this is a keyword. 
                            break;
                    } 
 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.MethodDirectionMismatch, argPosition, methodName, dirString);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodDirectionMismatch); 

                    return false;
                }
 
                if (this.type.IsByRef && this.type != argument.type)
                { 
                    // If the parameter is "ref" or "out", then the types must match exactly. 
                    // If not, this method can't be a candidate.
 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type));
                    error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);

                    return false; 
                }
 
                // If the argument type is not assignable to the corresponding parameter type, 
                // this method can't be a candidate.
                if (!RuleValidation.TypesAreAssignable(argument.type, this.type, argument.expression, out error)) 
                {
                    if (error == null)
                    {
                        message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type)); 
                        error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);
                    } 
                    return false; 
                }
 
                // If we passed the above checks, this argument is a candidate match for the parameter.
                return true;
            }
 
            public override bool Equals(object obj)
            { 
                CandidateParameter otherParam = obj as CandidateParameter; 
                if (otherParam == null)
                    return false; 

                return this.direction == otherParam.direction && this.type == otherParam.type;
            }
 
            public override int GetHashCode()
            { 
                return this.direction.GetHashCode() ^ this.type.GetHashCode(); 
            }
 
            internal int CompareConversion(CandidateParameter otherParam, Argument argument)
            {
                // Return 0 if they are equal; 1 if this is better; -1 if this is worse.
                // This follows the C# specification 7.4.2.3 
                int better = 1;
                int worse = -1; 
                int equal = 0; 

                // If the two candidate parameters have the same type, neither one is better. 
                if (this.type == otherParam.type)
                    return equal;

                // If the argument type is the same as one of the parameter types, that parameter is better. 
                if (argument.type == this.type)
                    return better; 
                if (argument.type == otherParam.type) 
                    return worse;
 
                // If this parameter can be converted to the other parameter, and not vice versa, then
                // this is a better conversion.  (And in the reverse situation, it's a worse conversion.)
                ValidationError dummy;
                bool thisConvertsToOther = RuleValidation.TypesAreAssignable(this.type, otherParam.type, null, out dummy); 
                bool otherConvertsToThis = RuleValidation.TypesAreAssignable(otherParam.type, this.type, null, out dummy);
                if (thisConvertsToOther && !otherConvertsToThis) 
                    return better; 
                if (otherConvertsToThis && !thisConvertsToOther)
                    return worse; 

                // See if one is a better sign-preserving conversion than the other.
                if (BetterSignedConversion(this.type, otherParam.type))
                    return better; 
                if (BetterSignedConversion(otherParam.type, this.type))
                    return worse; 
 
                // Otherwise, neither conversion is better.
                return equal; 
            }

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
            private static bool BetterSignedConversion(Type t1, Type t2) 
            {
                TypeCode tc1 = Type.GetTypeCode(t1); 
                TypeCode tc2 = Type.GetTypeCode(t2); 

                switch (tc1) 
                {
                    case TypeCode.SByte:
                        switch (tc2)
                        { 
                            case TypeCode.Byte:
                            case TypeCode.UInt16: 
                            case TypeCode.UInt32: 
                            case TypeCode.UInt64:
                                // A conversion to sbyte is better than a conversion to an unsigned type. 
                                return true;
                        }
                        break;
 
                    case TypeCode.Int16:
                        switch (tc2) 
                        { 
                            case TypeCode.UInt16:
                            case TypeCode.UInt32: 
                            case TypeCode.UInt64:
                                // A conversion to short is better than a conversion to an unsigned type.
                                return true;
                        } 
                        break;
 
                    case TypeCode.Int32: 
                        if (tc2 == TypeCode.UInt32 || tc2 == TypeCode.UInt64)
                        { 
                            // A conversion to int is better than a conversion to an unsigned type.
                            return true;
                        }
                        break; 

                    case TypeCode.Int64: 
                        if (tc2 == TypeCode.UInt64) 
                        {
                            // A conversion to long is better than a conversion to an unsigned type. 
                            return true;
                        }
                        break;
 
                    case TypeCode.Object:
                        // it is possible that the types are nullable 
                        if (ConditionHelper.IsNullableValueType(t1)) 
                        {
                            t1 = t1.GetGenericArguments()[0]; 
                            // t2 may already be a value type
                            if (ConditionHelper.IsNullableValueType(t2))
                                t2 = t2.GetGenericArguments()[0];
                            return BetterSignedConversion(t1, t2); 
                        }
                        return false; 
                } 

                return false; 
            }
        }

        private class CandidateMember 
        {
            internal enum Form 
            { 
                Normal,     // no "params" expansion
                Expanded    // matched only after "params" expansion 
            }

            internal MemberInfo Member;
            private ParameterInfo[] memberParameters; 
            private List signature;
            private Form form; 
            private static ParameterInfo[] noParameters = new ParameterInfo[0]; 
            private static List noSignature = new List();
 
            // Constructor for candidate methods with parameters.
            internal CandidateMember(MemberInfo member, ParameterInfo[] parameters, List signature, Form form)
            {
                this.Member = member; 
                this.memberParameters = parameters;
                this.signature = signature; 
                this.form = form; 
            }
 
            // Constructor for a candidate method that has no parameters.
            internal CandidateMember(MemberInfo member)
                : this(member, noParameters, noSignature, Form.Normal)
            { 
            }
 
            internal bool IsExpanded 
            {
                get { return form == Form.Expanded; } 
            }

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
            internal int CompareMember(Type targetType, CandidateMember other, List arguments, RuleValidation validator) 
            {
                int better = 1; 
                int worse = -1; 
                int equal = 0;
 
                // Methods in a base class are not candidates if any method in a derived class
                // is applicable.
                Type thisDeclaringType = this.Member.DeclaringType;
                Type otherDeclaringType = other.Member.DeclaringType; 
                if (thisDeclaringType != otherDeclaringType)
                { 
                    if (TypeProvider.IsAssignable(otherDeclaringType, thisDeclaringType)) 
                    {
                        // This declaring type can be converted to the other declaring type, 
                        // which means this one is more derived.
                        return better;
                    }
                    else if (TypeProvider.IsAssignable(thisDeclaringType, otherDeclaringType)) 
                    {
                        // The other declaring type can be converted to this declaring type, 
                        // which means the other one is more derived. 
                        return worse;
                    } 
                }

                System.Diagnostics.Debug.Assert(arguments.Count == this.signature.Count);
                System.Diagnostics.Debug.Assert(arguments.Count == other.signature.Count); 

                bool hasAtLeastOneBetterConversion = false; 
                bool hasAtLeastOneWorseConversion = false; 
                bool signaturesAreIdentical = true;
 
                // pick non-extension methods over extension methods
                // if both are extension methods, then pick the one in the namespace closest to "this"
                ExtensionMethodInfo thisExtension = this.Member as ExtensionMethodInfo;
                ExtensionMethodInfo otherExtension = other.Member as ExtensionMethodInfo; 
                if ((thisExtension == null) && (otherExtension != null))
                    return better; 
                else if ((thisExtension != null) && (otherExtension == null)) 
                    return worse;
                else if ((thisExtension != null) && (otherExtension != null)) 
                {
                    // we have 2 extension methods, which one is better
                    string[] thisNameSpace = thisExtension.DeclaringType.FullName.Split('.');
                    string[] otherNameSpace = otherExtension.DeclaringType.FullName.Split('.'); 
                    string[] bestNameSpace = validator.thisType.FullName.Split('.');
                    int thisMatch = MatchNameSpace(thisNameSpace, bestNameSpace); 
                    int otherMatch = MatchNameSpace(otherNameSpace, bestNameSpace); 
                    if (thisMatch > otherMatch)
                        return better; 
                    else if (thisMatch < otherMatch)
                        return worse;

                    // compare arguments, including the "this" argument 
                    CandidateParameter thisDeclaringParam = new CandidateParameter(thisExtension.AssumedDeclaringType);
                    CandidateParameter otherDeclaringParam = new CandidateParameter(otherExtension.AssumedDeclaringType); 
                    if (!thisDeclaringParam.Equals(otherDeclaringParam)) 
                    {
                        signaturesAreIdentical = false; 
                        int conversionResult = thisDeclaringParam.CompareConversion(otherDeclaringParam, new Argument(targetType));
                        if (conversionResult < 0)
                        {
                            // A conversion was found that was worse, so this candidate is not better. 
                            hasAtLeastOneWorseConversion = true;
                        } 
                        else if (conversionResult > 0) 
                        {
                            // This candidate had at least one conversion that was better.  (But 
                            // we have to keep looking in case there's one that's worse.)
                            hasAtLeastOneBetterConversion = true;
                        }
                    } 

                    // this check compares parameter lists correctly (see below) 
                    for (int p = 0; p < arguments.Count; ++p) 
                    {
                        CandidateParameter thisParam = this.signature[p]; 
                        CandidateParameter otherParam = other.signature[p];

                        if (!thisParam.Equals(otherParam))
                            signaturesAreIdentical = false; 

                        int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); 
                        if (conversionResult < 0) 
                        {
                            // A conversion was found that was worse, so this candidate is not better. 
                            hasAtLeastOneWorseConversion = true;
                        }
                        else if (conversionResult > 0)
                        { 
                            // This candidate had at least one conversion that was better.  (But
                            // we have to keep looking in case there's one that's worse.) 
                            hasAtLeastOneBetterConversion = true; 
                        }
                    } 
                    if (hasAtLeastOneBetterConversion && !hasAtLeastOneWorseConversion)
                    {
                        // At least one conversion was better than the "other" candidate
                        // and no other arguments were worse, so this one is better. 
                        return better;
                    } 
                    else if (!hasAtLeastOneBetterConversion && hasAtLeastOneWorseConversion) 
                    {
                        // At least one conversion was worse than the "other" candidate 
                        // and no other arguments were better, so this one is worse.
                        return worse;
                    }
                } 
                else
                { 
                    // NOTE: this is the original v1 code 
                    // It doesn't check for worse parameters correctly.
                    // However, for backwards compatability, we can't change it 
                    for (int p = 0; p < arguments.Count; ++p)
                    {
                        CandidateParameter thisParam = this.signature[p];
                        CandidateParameter otherParam = other.signature[p]; 

                        if (!thisParam.Equals(otherParam)) 
                            signaturesAreIdentical = false; 

                        int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); 
                        if (conversionResult < 0)
                        {
                            // A conversion was found that was worse, so this candidate is not better.
                            return worse; 
                        }
                        else if (conversionResult > 0) 
                        { 
                            // This candidate had at least one conversion that was better.  (But
                            // we have to keep looking in case there's one that's worse.) 
                            hasAtLeastOneBetterConversion = true;
                        }
                    }
 
                    if (hasAtLeastOneBetterConversion)
                    { 
                        // At least one conversion was better than the "other" candidate, so this one 
                        // is better.
                        return better; 
                    }
                }

                if (signaturesAreIdentical) 
                {
                    // The signatures were "tied".  Try some disambiguating rules for expanded signatures 
                    // vs normal signatures. 
                    if (this.form == Form.Normal && other.form == Form.Expanded)
                    { 
                        // This candidate matched in its normal form, but the other one matched only after
                        // expansion of a params array.  This one is better.
                        return better;
                    } 
                    else if (this.form == Form.Expanded && other.form == Form.Normal)
                    { 
                        // This candidate matched in its expanded form, but the other one matched in its 
                        // normal form.  The other one was better.
                        return worse; 
                    }
                    else if (this.form == Form.Expanded && other.form == Form.Expanded)
                    {
                        // Both candidates matched in their expanded forms. 

                        int thisParameterCount = this.memberParameters.Length; 
                        int otherParameterCount = other.memberParameters.Length; 

                        if (thisParameterCount > otherParameterCount) 
                        {
                            // This candidate had more declared parameters, so it is better.
                            return better;
                        } 
                        else if (otherParameterCount > thisParameterCount)
                        { 
                            // The other candidate had more declared parameters, so it was better. 
                            return worse;
                        } 
                    }
                }

                // Nothing worked, the two candidates are equally applicable. 
                return equal;
            } 
 
            private static int MatchNameSpace(string[] test, string[] reference)
            { 
                // returns the number of strings in test that are the same as reference
                int i;
                int len = Math.Min(test.Length, reference.Length);
                for (i = 0; i < len; ++i) 
                {
                    if (test[i] != reference[i]) 
                        break; 
                }
                return i; 
            }
        }

        // Get the candidate target types, ordered from most-derived to least-derived. 
        private static List GetCandidateTargetTypes(Type targetType)
        { 
            List candidateTypes; 

            if (targetType.IsInterface) 
            {
                candidateTypes = new List();
                candidateTypes.Add(targetType);
 
                // Add all base interfaces in its hierarchy to the candidate list.
                for (int i = 0; i < candidateTypes.Count; ++i) 
                { 
                    Type currentCandidate = candidateTypes[i];
                    candidateTypes.AddRange(currentCandidate.GetInterfaces()); 
                }

                // Finally, add "System.Object", since all types intrinsically derive from this.
                candidateTypes.Add(typeof(object)); 
            }
            else 
            { 
                // It was a class; just add the one class.
                candidateTypes = new List(1); 
                candidateTypes.Add(targetType);
            }

            return candidateTypes; 
        }
 
        private delegate ValidationError BuildArgCountMismatchError(string name, int numArguments); 

        private static void EvaluateCandidate(List candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError) 
        {
            error = null;

            int numArguments = arguments.Count; 
            string candidateName = candidateMember.Name;
 
            if (parameters == null || parameters.Length == 0) 
            {
                // If there were no arguments supplied, and this method has no parameters, 
                // then it's a candidate.  (It should be the only one.)
                if (numArguments == 0)
                {
                    candidates.Add(new CandidateMember(candidateMember)); 
                }
                else 
                { 
                    error = buildArgCountMismatchError(candidateName, numArguments);
                } 
            }
            else
            {
                List signature = new List(); 

                int parameterCount = parameters.Length; 
 
                int fixedParameterCount = parameterCount;
 
                // Check to see if the last parameter is (1) an array and (2) has a ParamArrayAttribute
                // (i.e., it is a "params" array).
                ParameterInfo lastParam = parameters[parameterCount - 1];
                if (lastParam.ParameterType.IsArray) 
                {
                    object[] attrs = lastParam.GetCustomAttributes(typeof(ParamArrayAttribute), false); 
                    if (attrs != null && attrs.Length > 0) 
                        fixedParameterCount -= 1;
                } 

                if (numArguments < fixedParameterCount)
                {
                    // Not enough arguments were passed for this to be a candidate. 
                    error = buildArgCountMismatchError(candidateName, numArguments);
 
                    return; 
                }
                else if (fixedParameterCount == parameterCount && numArguments != parameterCount) 
                {
                    // Too many arguments were passed for this to be a candidate.
                    error = buildArgCountMismatchError(candidateName, numArguments);
 
                    return;
                } 
 
                // For the fixed part of the method signature, make sure each argument can
                // be implicitly converted to the corresponding parameter. 
                int p = 0;
                for (; p < fixedParameterCount; ++p)
                {
                    CandidateParameter candidateParam = new CandidateParameter(parameters[p]); 
                    if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error))
                        break; // argument #p didn't match 
 
                    // If we get here, then so far so good.
                    signature.Add(candidateParam); 
                }

                if (p != fixedParameterCount)
                { 
                    // We didn't match all of the fixed part.  This method is not a candidate.
                    return; 
                } 

                if (fixedParameterCount < parameterCount) 
                {
                    // The last parameter was a "params" array.  As long as zero or more arguments
                    // are assignable, it's a valid candidate in the expanded form.
 
                    CandidateMember candidateMethod = null;
 
                    if (numArguments == fixedParameterCount) 
                    {
                        // Zero arguments were passed as the params array.  The method is a candidate 
                        // in its expanded form.
                        candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
                    }
                    else if (numArguments == parameterCount) 
                    {
                        // Special case:  one argument was passed as the params array. 
                        CandidateParameter candidateParam = new CandidateParameter(lastParam); 
                        if (candidateParam.Match(arguments[p], candidateName, p + 1, out error))
                        { 
                            // It was the same array type as the params array, so the candidate
                            // matched in its normal form.
                            signature.Add(candidateParam);
                            candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal); 
                        }
                    } 
 
                    if (candidateMethod == null)
                    { 
                        // One or more arguments were passed as the params array.  As long
                        // as they match the element type, this method is a candidate.
                        CandidateParameter candidateParam = new CandidateParameter(lastParam.ParameterType.GetElementType());
 
                        for (; p < numArguments; ++p)
                        { 
                            if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error)) 
                            {
                                // Not all of the trailing arguments matched the params array's element type; 
                                // this cannot be a candidate.
                                return;
                            }
 
                            // If we get here, then so far so good.
                            signature.Add(candidateParam); 
                        } 

                        // All the trailing arguments matched, so this is a candidate in the expanded form. 
                        candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
                    }

                    candidates.Add(candidateMethod); 
                }
                else 
                { 
                    // The last parameter wasn't "params".  This candidate matched in its normal form.
                    candidates.Add(new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal)); 
                }
            }
        }
 
        private CandidateMember FindBestCandidate(Type targetType, List candidates, List arguments)
        { 
            int numCandidates = candidates.Count; 
            Debug.Assert(numCandidates > 0, "expected at least one candidate");
 
            // Start by assuming the first candidate is the best one.
            List bestCandidates = new List(1);
            bestCandidates.Add(candidates[0]);
 
            // Go through the rest of the candidates and try to find a better one.  (If
            // there are no more candidates, then there was only one, and that's the right 
            // one.) 
            for (int i = 1; i < numCandidates; ++i)
            { 
                CandidateMember newCandidate = candidates[i];

                // Compare this new candidate one if the current "best" ones.  (If there
                // is currently more than one best candidate, then so far its ambiguous, which 
                // means all the best ones are equally good.  Thus if this new candidate
                // is better than one, it's better than all. 
                CandidateMember bestCandidate = bestCandidates[0]; 

                int comparison = newCandidate.CompareMember(targetType, bestCandidate, arguments, this); 
                if (comparison > 0)
                {
                    // The new one was better than at least one of the best ones.  It
                    // becomes the new best one. 
                    bestCandidates.Clear();
                    bestCandidates.Add(newCandidate); 
                } 
                else if (comparison == 0)
                { 
                    // The new one was no better, so add it to the list of current best.
                    // (Unless we find a better one, it's ambiguous so far.)
                    bestCandidates.Add(newCandidate);
                } 
            }
 
            if (bestCandidates.Count == 1) 
            {
                // Good, there was exactly one best match. 
                return bestCandidates[0];
            }

            // Otherwise, it must have been ambiguous. 
            return null;
        } 
 
        internal MethodInfo FindBestCandidate(Type targetType, List methods, params Type[] types)
        { 
            List arguments = new List();
            foreach (Type t in types)
                arguments.Add(new Argument(t));
 
            List candidates = new List(methods.Count);
            foreach (MethodInfo method in methods) 
            { 
                ValidationError tempError = null;
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError, 
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments);
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch); 
                                  });
            } 
            if (candidates.Count == 0) 
            {
                // nothing looks useful 
                return null;
            }
            CandidateMember result = FindBestCandidate(targetType, candidates, arguments);
            return (result != null) ? (MethodInfo)result.Member : null; 
        }
 
        internal RuleConstructorExpressionInfo ResolveConstructor(Type targetType, BindingFlags constructorBindingFlags, List argumentExprs, out ValidationError error) 
        {
            string message; 

            List arguments = new List(argumentExprs.Count);
            foreach (CodeExpression argumentExpr in argumentExprs)
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all candidate methods contained in them. 
            List candidateTypes = GetCandidateTargetTypes(targetType); 
            // Get all methods by this name...
            List constructors = GetConstructors(candidateTypes, constructorBindingFlags); 
            if (constructors.Count == 0)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists); 
                return null;
            } 
 
            // Cull the list of methods to those which match the supplied arguments.
            List candidateConstructors = GetCandidateConstructors(constructors, arguments, out error); 

            // If the list is null, then no candidates matched.
            if (candidateConstructors == null)
                return null; 

            // We found candidate methods in this type. 
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateConstructors, arguments); 

            if (bestCandidate == null) 
            {
                // It was ambiguous.
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousConstructor, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                return null;
            } 
 
            // We found the best match.
            return new RuleConstructorExpressionInfo((ConstructorInfo)bestCandidate.Member, bestCandidate.IsExpanded); 
        }

        internal RuleMethodInvokeExpressionInfo ResolveMethod(Type targetType, string methodName, BindingFlags methodBindingFlags, List argumentExprs, out ValidationError error)
        { 
            string message;
 
            List arguments = new List(argumentExprs.Count); 
            foreach (CodeExpression argumentExpr in argumentExprs)
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all candidate methods contained in them.
            List candidateTypes = GetCandidateTargetTypes(targetType);
            // Get all methods by this name... 
            List methods = GetNamedMethods(candidateTypes, methodName, methodBindingFlags);
            if (methods.Count == 0) 
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownMethod, methodName, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists); 
                return null;
            }

            // Cull the list of methods to those which match the supplied arguments. 
            List candidateMethods = GetCandidateMethods(methodName, methods, arguments, out error);
 
            // If the list is null, then no candidates matched. 
            if (candidateMethods == null)
                return null; 

            // We found candidate methods in this type.
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateMethods, arguments);
 
            if (bestCandidate == null)
            { 
                // It was ambiguous. 
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousMatch, methodName);
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 

                return null;
            }
 
            // We found the best match.
            MethodInfo theMethod = (MethodInfo)bestCandidate.Member; 
            if (theMethod != null) 
            {
                IsAuthorized(theMethod.ReturnType); 
            }
            return new RuleMethodInvokeExpressionInfo(theMethod, bestCandidate.IsExpanded);
        }
 
        internal static List GetConstructors(List targetTypes, BindingFlags constructorBindingFlags)
        { 
            List methods = new List(); 

            for (int t = 0; t < targetTypes.Count; ++t) 
            {
                Type targetType = targetTypes[t];

                // Go through all the constructors on the target type 
                ConstructorInfo[] members = targetType.GetConstructors(constructorBindingFlags);
                for (int m = 0; m < members.Length; ++m) 
                { 
                    ConstructorInfo constructor = members[m];
                    if (constructor.IsGenericMethod) // skip generic constructors 
                        continue;
                    if (constructor.IsStatic) // skip static constructors
                        continue;
                    if (constructor.IsPrivate) // skip private constructors 
                        continue;
                    if (constructor.IsFamily) // skip internal constructors 
                        continue; 
                    methods.Add(constructor);
                } 
            }
            return methods;
        }
 
        private List GetNamedMethods(List targetTypes, string methodName, BindingFlags methodBindingFlags)
        { 
            List methods = new List(); 
            List currentExtensionMethods = ExtensionMethods;
            for (int t = 0; t < targetTypes.Count; ++t) 
            {
                Type targetType = targetTypes[t];

                // Go through all the methods on the target type that have matching names. 
                MemberInfo[] members = targetType.GetMember(methodName, MemberTypes.Method, methodBindingFlags);
                for (int m = 0; m < members.Length; ++m) 
                { 
                    MethodInfo method = (MethodInfo)members[m];
                    if (!method.IsGenericMethod) // skip generic methods 
                        methods.Add(method);
                }

                // add in any extension methods that match 
                foreach (ExtensionMethodInfo extension in currentExtensionMethods)
                { 
                    // does it have the right name and is the type compatible 
                    ValidationError error;
                    if ((extension.Name == methodName) && 
                        TypesAreAssignable(targetType, extension.AssumedDeclaringType, null, out error))
                    {
                        // possible match
                        methods.Add(extension); 
                    }
                } 
            } 

            return methods; 
        }

        private List extensionMethods;
        private List seenAssemblies; 
        private const string ExtensionAttributeFullName = "System.Runtime.CompilerServices.ExtensionAttribute, " + AssemblyRef.SystemCore;
        private Type extensionAttribute; 
 
        private static Type defaultExtensionAttribute = GetDefaultExtensionAttribute();
 
        private static Type GetDefaultExtensionAttribute()
        {
            return Type.GetType(ExtensionAttributeFullName, false);
        } 

        // The extensionAttributeType may still be null after calling this method 
        // if, for example, we are in a 3.0 SP2 environment. 
        private void SetExtensionAttribute()
        { 
            // use the TypeProvider first
            extensionAttribute = typeProvider.GetType(ExtensionAttributeFullName, false);
            if (extensionAttribute == null)
            { 
                extensionAttribute = defaultExtensionAttribute;
            } 
        } 

        internal List ExtensionMethods 
        {
            get
            {
                if (extensionMethods == null) 
                    DetermineExtensionMethods();
 
                return extensionMethods; 
            }
        } 

        private void DetermineExtensionMethods()
        {
            extensionMethods = new List(); 

            SetExtensionAttribute(); 
            if (extensionAttribute != null) 
            {
                seenAssemblies = new List(); 
                Assembly localAssembly = typeProvider.LocalAssembly;
                if (localAssembly != null)
                {
                    DetermineExtensionMethods(localAssembly); 
                    foreach (Assembly a in typeProvider.ReferencedAssemblies)
                        DetermineExtensionMethods(a); 
                } 
                else
                { 
                    // probably at design-time, nothing compiled yet
                    // go through all types it knows about
                    DetermineExtensionMethods(typeProvider.GetTypes());
                } 
            }
        } 
 
        internal void DetermineExtensionMethods(Assembly assembly)
        { 
            // when this method is called outside of this class, we must have tried
            // getting ExtensionMethods. So we must have tried setting extensionAttributeType.

            if (extensionAttribute != null) 
            {
                if ((assembly != null) && (!seenAssemblies.Contains(assembly))) 
                { 
                    seenAssemblies.Add(assembly);
                    if (IsMarkedExtension(assembly)) 
                    {
                        Type[] types;
                        try
                        { 
                            types = assembly.GetTypes();
                        } 
                        catch (ReflectionTypeLoadException e) 
                        {
                            // problems loading all the types, take what we can get 
                            // some types will be null
                            types = e.Types;
                        }
                        DetermineExtensionMethods(types); 
                    }
                } 
            } 
        }
 
        private void DetermineExtensionMethods(Type[] types)
        {
            foreach (Type type in types)
            { 
                // static classes are defined as "abstract sealed"
                // Note: VB doesn't support static classes, so the modules are only defined as "sealed" 
                if ((type != null) && (type.IsPublic || type.IsNestedPublic) && (type.IsSealed) && (IsMarkedExtension(type))) 
                {
                    // looks like a class containing extension methods, let's find them 
                    MethodInfo[] staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
                    foreach (MethodInfo mi in staticMethods)
                    {
                        // skip generic methods 
                        if ((mi.IsStatic) && !(mi.IsGenericMethod) && (IsMarkedExtension(mi)))
                        { 
                            ParameterInfo[] parms = mi.GetParameters(); 
                            if (parms.Length > 0 && parms[0].ParameterType != null)
                            { 
                                extensionMethods.Add(new ExtensionMethodInfo(mi, parms));
                            }
                        }
                    } 
                }
            } 
        } 

        private bool IsMarkedExtension(Assembly assembly) 
        {
            if (extensionAttribute != null)
            {
                object[] objAttrs = assembly.GetCustomAttributes(extensionAttribute, false); 
                if (objAttrs != null && objAttrs.Length > 0)
                    return true; 
            } 

            return false; 
        }

        private bool IsMarkedExtension(Type type)
        { 
            if (extensionAttribute != null)
            { 
                object[] objAttrs = type.GetCustomAttributes(extensionAttribute, false); 
                if (objAttrs != null && objAttrs.Length > 0)
                    return true; 
            }

            return false;
        } 

        private bool IsMarkedExtension(MethodInfo mi) 
        { 
            if (extensionAttribute != null)
            { 
                object[] objAttrs = mi.GetCustomAttributes(extensionAttribute, false);
                if (objAttrs != null && objAttrs.Length > 0)
                    return true;
            } 

            return false; 
        } 

        static List GetCandidateMethods(string methodName, List methods, List arguments, out ValidationError error) 
        {
            List candidates = new List();

            error = null; 

            int errorCount = 0; 
            foreach (MethodInfo method in methods) 
            {
                ValidationError tempError = null; 
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments); 
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
                                  }); 
 
                error = tempError;
                if (tempError != null) 
                    ++errorCount;
            }

            if (candidates.Count == 0) 
            {
                // No candidates were found. 
 
                if (errorCount > 1)
                { 
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodOverloadNotFound, methodName);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound); 
                }
 
                return null; 
            }
            else 
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null;
            } 

            return candidates; 
        } 

        static List GetCandidateConstructors(List constructors, List arguments, out ValidationError error) 
        {
            List candidates = new List();

            error = null; 

            int errorCount = 0; 
            foreach (ConstructorInfo method in constructors) 
            {
                ValidationError tempError = null; 
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments); 
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
                                  }); 
 
                error = tempError;
                if (tempError != null) 
                    ++errorCount;
            }

            if (candidates.Count == 0) 
            {
                // No candidates were found. 
 
                if (errorCount > 1)
                { 
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.ConstructorOverloadNotFound);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound); 
                }
 
                return null; 
            }
            else 
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null;
            } 

            return candidates; 
        } 

        internal RulePropertyExpressionInfo ResolveIndexerProperty(Type targetType, BindingFlags bindingFlags, List argumentExprs, out ValidationError error) 
        {
            string message;

            int numArgs = argumentExprs.Count; 

            if (numArgs < 1) 
            { 
                // Must have at least one indexer!
                message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArgs); 
                error = new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch);
                return null;
            }
 
            List arguments = new List(numArgs);
            foreach (CodeExpression argumentExpr in argumentExprs) 
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all the candidate indexer properties contained in them. 
            List candidateTypes = GetCandidateTargetTypes(targetType);
            List indexerProperties = GetIndexerProperties(candidateTypes, bindingFlags);
            if (indexerProperties.Count == 0)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerNotFound, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_IndexerNotFound); 
                return null; 
            }
 
            List candidateIndexers = GetCandidateIndexers(indexerProperties, arguments, out error);

            // If the list is null, then no candidates matched.
            if (candidateIndexers == null) 
                return null;
 
            // We found candidate methods in this type. 
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateIndexers, arguments);
 
            if (bestCandidate == null)
            {
                // It was ambiguous.
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousIndexerMatch); 
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
 
                return null; 
            }
 
            // We found the best match.
            PropertyInfo pi = (PropertyInfo)bestCandidate.Member;
            if (pi != null)
            { 
                IsAuthorized(pi.PropertyType);
            } 
            return new RulePropertyExpressionInfo(pi, pi.PropertyType, bestCandidate.IsExpanded); 
        }
 
        private static List GetIndexerProperties(List candidateTypes, BindingFlags bindingFlags)
        {
            List indexerProperties = new List();
 
            foreach (Type targetType in candidateTypes)
            { 
                object[] attrs = targetType.GetCustomAttributes(typeof(DefaultMemberAttribute), true); 
                if (attrs == null || attrs.Length == 0)
                    continue; 

                DefaultMemberAttribute[] defaultMemberAttrs = (DefaultMemberAttribute[])attrs;

                PropertyInfo[] properties = targetType.GetProperties(bindingFlags); 
                for (int p = 0; p < properties.Length; ++p)
                { 
                    PropertyInfo pi = properties[p]; 

                    // Select only those properties whose name matches the default name. 
                    bool matchedName = false;
                    for (int dm = 0; dm < defaultMemberAttrs.Length; ++dm)
                    {
                        if (defaultMemberAttrs[dm].MemberName == pi.Name) 
                        {
                            matchedName = true; 
                            break; 
                        }
                    } 

                    if (matchedName)
                    {
                        // We matched the name... 
                        ParameterInfo[] indexerParameters = pi.GetIndexParameters();
                        if (indexerParameters.Length > 0) 
                        { 
                            // ... and have indexer parameters; therefore, this is
                            // an interesting property. 
                            indexerProperties.Add(pi);
                        }
                    }
                } 
            }
 
            return indexerProperties; 
        }
 
        private static List GetCandidateIndexers(List indexerProperties, List arguments, out ValidationError error)
        {
            List candidates = new List();
 
            error = null;
 
            int errorCount = 0; 
            foreach (PropertyInfo indexerProp in indexerProperties)
            { 
                ValidationError tempError = null;
                EvaluateCandidate(candidates, indexerProp, indexerProp.GetIndexParameters(), arguments, out tempError,
                                  delegate(string propName, int numArguments)
                                  { 
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArguments);
                                      return new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch); 
                                  }); 

                error = tempError; 
                if (tempError != null)
                    ++errorCount;
            }
 
            if (candidates.Count == 0)
            { 
                // No candidates were found. 

                if (errorCount > 1) 
                {
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerOverloadNotFound); 
                    error = new ValidationError(message, ErrorNumbers.Error_IndexerOverloadNotFound);
                } 
 
                return null;
            } 
            else
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null; 
            }
 
            return candidates; 
        }
 
        #endregion

        #region Type resolution
 
        internal void AddTypeReference(CodeTypeReference typeRef, Type type)
        { 
            typeRefMap[typeRef] = type; 
        }
 
        internal Type ResolveType(CodeTypeReference typeRef)
        {
            Type resultType = null;
 
            if (!typeRefMap.TryGetValue(typeRef, out resultType))
            { 
                string message; 

                resultType = FindType(typeRef.BaseType); 

                if (resultType == null)
                {
                    // check if we have a qualifiedname saved, and if we do, use it 
                    string qualifiedName = typeRef.UserData[RuleUserDataKeys.QualifiedName] as string;
                    resultType = ResolveType(qualifiedName); 
                    if (resultType != null) 
                    {
                        // qualified name returned the complete type, save it and we're done 
                        typeRefMap.Add(typeRef, resultType);
                        return resultType;
                    }
                    message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownType, typeRef.BaseType); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType);
                    error.UserData[RuleUserDataKeys.ErrorObject] = typeRef; 
                    Errors.Add(error); 
                    return null;
                } 

                // Handle generic type arguments.
                if (typeRef.TypeArguments.Count > 0)
                { 
                    Type[] typeArguments = new Type[typeRef.TypeArguments.Count];
                    for (int i = 0; i < typeRef.TypeArguments.Count; ++i) 
                    { 
                        // design-time types don't have fully-qualified names, so when they are
                        // used in a generic CodeTypeReference constructor leaves them with [] 
                        // surrounding them. Remove the [] if possible
                        CodeTypeReference arg = typeRef.TypeArguments[i];
                        if (arg.BaseType.StartsWith("[", StringComparison.Ordinal))
                            arg.BaseType = arg.BaseType.Substring(1, arg.BaseType.Length - 2); 

                        typeArguments[i] = ResolveType(arg); 
                        if (typeArguments[i] == null) 
                            return null;
                    } 

                    resultType = resultType.MakeGenericType(typeArguments);
                    if (resultType == null)
                    { 
                        StringBuilder sb = new StringBuilder(typeRef.BaseType);
                        string prefix = "<"; 
                        foreach (Type t in typeArguments) 
                        {
                            sb.Append(prefix); 
                            prefix = ",";
                            sb.Append(RuleDecompiler.DecompileType(t));
                        }
                        sb.Append(">"); 
                        message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownGenericType, sb.ToString());
                        ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType); 
                        error.UserData[RuleUserDataKeys.ErrorObject] = typeRef; 
                        Errors.Add(error);
                        return null; 
                    }
                }

 
                if (resultType != null)
                { 
                    CodeTypeReference arrayTypeRef = typeRef; 
                    if (arrayTypeRef.ArrayRank > 0)
                    { 
                        do
                        {
                            resultType = (arrayTypeRef.ArrayRank == 1) ? resultType.MakeArrayType() : resultType.MakeArrayType(arrayTypeRef.ArrayRank);
 
                            arrayTypeRef = arrayTypeRef.ArrayElementType;
                        } while (arrayTypeRef.ArrayRank > 0); 
                    } 
                }
 
                if (resultType != null)
                {
                    typeRefMap.Add(typeRef, resultType);
 
                    // at runtime we may not have the assembly loaded, so keep the fully qualified name around
                    typeRef.UserData[RuleUserDataKeys.QualifiedName] = resultType.AssemblyQualifiedName; 
                } 
            }
 
            return resultType;
        }

        internal Type ResolveType(string qualifiedName) 
        {
            Type resultType = null; 
            if (qualifiedName != null) 
            {
                resultType = typeProvider.GetType(qualifiedName, false); 

                // if the Typeprovider can't find it, use the framework,
                // since it should be an AssemblyQualifiedName
                if (resultType == null) 
                    resultType = Type.GetType(qualifiedName, false);
 
            } 
            return resultType;
        } 

        private Type FindType(string typeName)
        {
            if (typeName == null) 
                throw new ArgumentNullException("typeName");
 
            Type type = null; 

            // do we know about this type 
            if (!typesUsed.TryGetValue(typeName, out type))
            {
                type = typeProvider.GetType(typeName, false);
 
                if (type != null)
                { 
                    typesUsed.Add(typeName, type); 

                    IsAuthorized(type); 
                }
            }

            return type; 
        }
 
        internal void IsAuthorized(Type type) 
        {
            Debug.Assert(!type.IsPointer && !type.IsByRef, 
            "IsAuthorized should not be called for a type that is a pointer or passed by reference : " + type.AssemblyQualifiedName);
            if (checkStaticType)
            {
                if (authorizedTypes == null) 
                {
                    ValidationError error = new ValidationError(Messages.Error_ConfigFileMissingOrInvalid, ErrorNumbers.Error_ConfigFileMissingOrInvalid); 
                    Errors.Add(error); 
                }
                else 
                {
                    while (type.IsArray)
                    {
                        type = type.GetElementType(); 
                    }
                    if (type.IsGenericType) 
                    { 
                        IsAuthorizedSimpleType(type.GetGenericTypeDefinition());
                        Type[] typeArguments = type.GetGenericArguments(); 
                        foreach (Type t in typeArguments)
                        {
                            IsAuthorized(t);
                        } 
                    }
                    else 
                    { 
                        IsAuthorizedSimpleType(type);
                    } 
                }
            }
        }
 
        void IsAuthorizedSimpleType(Type type)
        { 
            Debug.Assert((!type.IsGenericType || type.IsGenericTypeDefinition) && !type.HasElementType, 
                "IsAuthorizedSimpleType should not be called for a partially specialized generic type or a type that encompasses or refers to another type : " +
                type.AssemblyQualifiedName); 

            string qualifiedName = type.AssemblyQualifiedName;

            if (!typesUsedAuthorized.ContainsKey(qualifiedName)) 
            {
                bool authorized = false; 
                foreach (AuthorizedType authorizedType in authorizedTypes) 
                {
                    if (authorizedType.RegularExpression.IsMatch(qualifiedName)) 
                    {
                        authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0);
                        if (!authorized)
                            break; 
                    }
                } 
                if (!authorized) 
                {
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.Error_TypeNotAuthorized, type.FullName); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_TypeNotAuthorized);
                    error.UserData[RuleUserDataKeys.ErrorObject] = type;
                    Errors.Add(error);
                } 
                else
                { 
                    typesUsedAuthorized.Add(qualifiedName, type); 
                }
            } 
        }

        #endregion
 
        #endregion
    } 
    #endregion RuleValidator 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
// ---------------------------------------------------------------------------- 
// Copyright (C) 2006 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------

#define CODE_ANALYSIS 
using System.CodeDom;
using System.Collections.Generic; 
using System.Configuration; 
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis; 
using System.Globalization;
using System.Reflection;
using System.Text;
using System.Workflow.ComponentModel; 
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities.Common; 
 
namespace System.Workflow.Activities.Rules
{ 
    #region ExpressionInfo

    // Public base class (which just holds the Type of the expression).
    public class RuleExpressionInfo 
    {
        private Type expressionType; 
 
        public RuleExpressionInfo(Type expressionType)
        { 
            this.expressionType = expressionType;
        }

        public Type ExpressionType 
        {
            get { return expressionType; } 
        } 
    }
 
    // Internal derivation for CodeMethodInvokeExpression
    internal class RuleMethodInvokeExpressionInfo : RuleExpressionInfo
    {
        private MethodInfo methodInfo; 
        private bool needsParamsExpansion;
 
        internal RuleMethodInvokeExpressionInfo(MethodInfo mi, bool needsParamsExpansion) 
            : base(mi.ReturnType)
        { 
            this.methodInfo = mi;
            this.needsParamsExpansion = needsParamsExpansion;
        }
 
        internal MethodInfo MethodInfo
        { 
            get { return methodInfo; } 
        }
 
        internal bool NeedsParamsExpansion
        {
            get { return needsParamsExpansion; }
        } 
    }
 
    // Internal derivation for CodeBinaryExpression 
    internal class RuleBinaryExpressionInfo : RuleExpressionInfo
    { 
        private Type leftType;
        private Type rightType;
        private MethodInfo methodInfo;
 
        // no overridden method needed
        internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, Type resultType) 
            : base(resultType) 
        {
            this.leftType = lhsType; 
            this.rightType = rhsType;
        }

        // overridden method found 
        internal RuleBinaryExpressionInfo(Type lhsType, Type rhsType, MethodInfo mi)
            : base(mi.ReturnType) 
        { 
            this.leftType = lhsType;
            this.rightType = rhsType; 
            this.methodInfo = mi;
        }

        internal Type LeftType 
        {
            get { return leftType; } 
        } 

        internal Type RightType 
        {
            get { return rightType; }
        }
 
        internal MethodInfo MethodInfo
        { 
            get { return methodInfo; } 
        }
    } 

    // Internal derivation for CodeFieldReferenceExpression
    internal class RuleFieldExpressionInfo : RuleExpressionInfo
    { 
        private FieldInfo fieldInfo;
 
        internal RuleFieldExpressionInfo(FieldInfo fi) 
            : base(fi.FieldType)
        { 
            fieldInfo = fi;
        }

        internal FieldInfo FieldInfo 
        {
            get { return fieldInfo; } 
        } 
    }
 
    // Internal derivation for CodePropertyReferenceExpression
    internal class RulePropertyExpressionInfo : RuleExpressionInfo
    {
        private PropertyInfo propertyInfo; 
        private bool needsParamsExpansion;
 
        // Note that the type pi.PropertyType may differ from the "exprType" argument if this 
        // property is a Bind.
        internal RulePropertyExpressionInfo(PropertyInfo pi, Type exprType, bool needsParamsExpansion) 
            : base(exprType)
        {
            this.propertyInfo = pi;
            this.needsParamsExpansion = needsParamsExpansion; 
        }
 
        internal PropertyInfo PropertyInfo 
        {
            get { return propertyInfo; } 
        }

        internal bool NeedsParamsExpansion
        { 
            get { return needsParamsExpansion; }
        } 
    } 

    // Internal derivation for CodeMethodInvokeExpression 
    internal class RuleConstructorExpressionInfo : RuleExpressionInfo
    {
        private ConstructorInfo constructorInfo;
        private bool needsParamsExpansion; 

        internal RuleConstructorExpressionInfo(ConstructorInfo ci, bool needsParamsExpansion) 
            : base(ci.DeclaringType) 
        {
            this.constructorInfo = ci; 
            this.needsParamsExpansion = needsParamsExpansion;
        }

        internal ConstructorInfo ConstructorInfo 
        {
            get { return constructorInfo; } 
        } 

        internal bool NeedsParamsExpansion 
        {
            get { return needsParamsExpansion; }
        }
    } 

    internal class ExtensionMethodInfo : MethodInfo 
    { 
        MethodInfo actualMethod;
        int actualParameterLength; 
        ParameterInfo[] expectedParameters;
        Type assumedDeclaringType;
        bool hasOutOrRefParameters = false;
 
        public ExtensionMethodInfo(MethodInfo method, ParameterInfo[] actualParameters)
            : base() 
        { 
            Debug.Assert(method.IsStatic, "Expected static method as an extension method");
 
            actualMethod = method;
            // modify parameters
            actualParameterLength = actualParameters.Length;
            if (actualParameterLength < 2) 
                expectedParameters = new ParameterInfo[0];
            else 
            { 
                expectedParameters = new ParameterInfo[actualParameterLength - 1];
                Array.Copy(actualParameters, 1, expectedParameters, 0, actualParameterLength - 1); 
                foreach (ParameterInfo pi in expectedParameters)
                {
                    if (pi.ParameterType.IsByRef)
                        hasOutOrRefParameters = true; 
                }
            } 
            // get the type we pretend this method is on (which happens to be the first actual parameter) 
            assumedDeclaringType = actualParameters[0].ParameterType;
        } 

        public override MethodInfo GetBaseDefinition()
        {
            return actualMethod.GetBaseDefinition(); 
        }
 
        public override ICustomAttributeProvider ReturnTypeCustomAttributes 
        {
            get { return actualMethod.ReturnTypeCustomAttributes; } 
        }

        public override MethodAttributes Attributes
        { 
            get { return actualMethod.Attributes & ~MethodAttributes.Static; }
        } 
 
        public override MethodImplAttributes GetMethodImplementationFlags()
        { 
            return actualMethod.GetMethodImplementationFlags();
        }

        public override ParameterInfo[] GetParameters() 
        {
            return expectedParameters; 
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        {
            object[] actualParameters = new object[actualParameterLength];
            if (actualParameterLength > 1)
                Array.Copy(parameters, 0, actualParameters, 1, actualParameterLength - 1); 
            if (obj == null)
                actualParameters[0] = null; 
            else 
                actualParameters[0] = Executor.AdjustType(obj.GetType(), obj, assumedDeclaringType);
            object result = actualMethod.Invoke(null, invokeAttr, binder, actualParameters, culture); 
            // may be out/ref parameters, so copy back the results
            if (hasOutOrRefParameters)
                Array.Copy(actualParameters, 1, parameters, 0, actualParameterLength - 1);
            return result; 
        }
 
        public override RuntimeMethodHandle MethodHandle 
        {
            get { return actualMethod.MethodHandle; } 
        }

        public override Type DeclaringType
        { 
            get { return actualMethod.DeclaringType; }
        } 
 
        public Type AssumedDeclaringType
        { 
            get { return assumedDeclaringType; }
        }

        public override object[] GetCustomAttributes(Type attributeType, bool inherit) 
        {
            return actualMethod.GetCustomAttributes(attributeType, inherit); 
        } 

        public override object[] GetCustomAttributes(bool inherit) 
        {
            return actualMethod.GetCustomAttributes(inherit);
        }
 
        public override bool IsDefined(Type attributeType, bool inherit)
        { 
            return actualMethod.IsDefined(attributeType, inherit); 
        }
 
        public override string Name
        {
            get { return actualMethod.Name; }
        } 

        public override Type ReflectedType 
        { 
            get { return actualMethod.ReflectedType; }
        } 

        public override Type ReturnType
        {
            get { return actualMethod.ReturnType; } 
        }
    } 
 
    internal class SimpleParameterInfo : ParameterInfo
    { 
        // only thing we look at is ParameterType, so no need to override anything else
        Type parameterType;

        public SimpleParameterInfo(ParameterInfo parameter) 
            : base()
        { 
            parameterType = typeof(Nullable<>).MakeGenericType(parameter.ParameterType); 
        }
 
        public SimpleParameterInfo(Type parameter)
            : base()
        {
            parameterType = parameter; 
        }
 
        public override Type ParameterType 
        {
            get 
            {
                return parameterType;
            }
        } 
    }
 
    internal abstract class BaseMethodInfo : MethodInfo 
    {
        protected MethodInfo actualMethod; 
        protected ParameterInfo[] expectedParameters;
        protected Type resultType;

        public BaseMethodInfo(MethodInfo method) 
            : base()
        { 
            Debug.Assert(method.IsStatic, "Expected static method as an lifted method"); 
            actualMethod = method;
            resultType = method.ReturnType; 
            expectedParameters = method.GetParameters();
        }

        public override MethodInfo GetBaseDefinition() 
        {
            return actualMethod.GetBaseDefinition(); 
        } 

        public override ICustomAttributeProvider ReturnTypeCustomAttributes 
        {
            get { return actualMethod.ReturnTypeCustomAttributes; }
        }
 
        public override MethodAttributes Attributes
        { 
            get { return actualMethod.Attributes & ~MethodAttributes.Static; } 
        }
 
        public override MethodImplAttributes GetMethodImplementationFlags()
        {
            return actualMethod.GetMethodImplementationFlags();
        } 

        public override ParameterInfo[] GetParameters() 
        { 
            return expectedParameters;
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        {
            throw new NotImplementedException(); 
        }
 
        public override RuntimeMethodHandle MethodHandle 
        {
            get { return actualMethod.MethodHandle; } 
        }

        public override Type DeclaringType
        { 
            get { return actualMethod.DeclaringType; }
        } 
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit)
        { 
            return actualMethod.GetCustomAttributes(attributeType, inherit);
        }

        public override object[] GetCustomAttributes(bool inherit) 
        {
            return actualMethod.GetCustomAttributes(inherit); 
        } 

        public override bool IsDefined(Type attributeType, bool inherit) 
        {
            return actualMethod.IsDefined(attributeType, inherit);
        }
 
        public override string Name
        { 
            get { return actualMethod.Name; } 
        }
 
        public override Type ReflectedType
        {
            get { return actualMethod.ReflectedType; }
        } 

        public override Type ReturnType 
        { 
            get { return resultType; }
        } 

        public override bool Equals(object obj)
        {
            BaseMethodInfo other = obj as BaseMethodInfo; 
            if ((other == null)
                || (actualMethod != other.actualMethod) 
                || (resultType != other.resultType) 
                || (expectedParameters.Length != other.expectedParameters.Length))
                return false; 
            for (int i = 0; i < expectedParameters.Length; ++i)
                if (expectedParameters[i].ParameterType != other.expectedParameters[i].ParameterType)
                    return false;
            return true; 
        }
 
        public override int GetHashCode() 
        {
            int result = actualMethod.GetHashCode() ^ resultType.GetHashCode(); 
            for (int i = 0; i < expectedParameters.Length; ++i)
                result ^= expectedParameters[i].GetHashCode();
            return result;
        } 
    }
 
    internal class LiftedConversionMethodInfo : BaseMethodInfo 
    {
        public LiftedConversionMethodInfo(MethodInfo method) 
            : base(method)
        {
            Debug.Assert(expectedParameters.Length == 1, "not 1 parameters");
 
            // modify result
            resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType); 
 
            // modify parameter (exactly 1)
            ParameterInfo[] actualParameters = method.GetParameters(); 
            expectedParameters = new ParameterInfo[1];
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
        }
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null in, then result is null 
            if (parameters[0] == null)
                return Activator.CreateInstance(resultType); 

            // invoke the conversion from S -> T
            object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
            // return a T? 
            return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
        } 
    } 

    internal class LiftedArithmeticOperatorMethodInfo : BaseMethodInfo 
    {
        public LiftedArithmeticOperatorMethodInfo(MethodInfo method)
            : base(method)
        { 
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");
 
            // modify parameters (exactly 2, both need to be lifted) 
            ParameterInfo[] actualParameters = method.GetParameters();
            expectedParameters = new ParameterInfo[2]; 
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);

            // modify result 
            resultType = typeof(Nullable<>).MakeGenericType(method.ReturnType);
        } 
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null in, then result is null
            if (parameters[0] == null)
                return null;
            if (parameters[1] == null) 
                return null;
 
            // apply the underlying operator 
            object result = actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
            // return a T? 
            return Executor.AdjustType(actualMethod.ReturnType, result, resultType);
        }
    }
 
    internal class LiftedEqualityOperatorMethodInfo : BaseMethodInfo
    { 
        public LiftedEqualityOperatorMethodInfo(MethodInfo method) 
            : base(method)
        { 
            Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters");

            // modify parameters (exactly 2, both need to be lifted) 
            ParameterInfo[] actualParameters = method.GetParameters();
            expectedParameters = new ParameterInfo[2]; 
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]); 
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
 
            // set the result type
            resultType = typeof(bool);
        }
 
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture)
        { 
            // null == null is true, null == something else is false, else call method 
            if (parameters[0] == null)
                return (parameters[1] == null); 
            else if (parameters[1] == null)
                return false;

            // invoke the actual comparison (parameters are unwrapped) 
            return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture);
        } 
    } 

    internal class LiftedRelationalOperatorMethodInfo : BaseMethodInfo 
    {
        public LiftedRelationalOperatorMethodInfo(MethodInfo method)
            : base(method)
        { 
            Debug.Assert(method.ReturnType == typeof(bool), "not a bool result");
            Debug.Assert(expectedParameters.Length == 2, "not 2 parameters"); 
 
            // modify parameters (exactly 2, both need to be lifted)
            ParameterInfo[] actualParameters = method.GetParameters(); 
            expectedParameters = new ParameterInfo[2];
            expectedParameters[0] = new SimpleParameterInfo(actualParameters[0]);
            expectedParameters[1] = new SimpleParameterInfo(actualParameters[1]);
 
            // set the result type
            resultType = typeof(bool); 
        } 

        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        {
            // if either parameter is null, then result is false
            if (parameters[0] == null)
                return false; 
            if (parameters[1] == null)
                return false; 
 
            // invoke the actual comparison (parameters are unwrapped)
            return actualMethod.Invoke(null, invokeAttr, binder, parameters, culture); 
        }
    }

    internal class EnumOperationMethodInfo : MethodInfo 
    {
        CodeBinaryOperatorType op; 
        ParameterInfo[] expectedParameters; 
        Type resultType;        // may be nullable, enum, or value type
        bool resultIsNullable;  // true if resultType is nullable 

        Type lhsBaseType;       // non-Nullable, may be enum
        Type rhsBaseType;
        Type resultBaseType; 

        Type lhsRootType;       // underlying type (int, long, ushort, etc) 
        Type rhsRootType; 
        Type resultRootType;
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        public EnumOperationMethodInfo(Type lhs, CodeBinaryOperatorType operation, Type rhs, bool isZero)
        {
            // only 5 arithmetic cases (U = underlying type of E): 
            //    E = E + U
            //    E = U + E 
            //    U = E - E 
            //    E = E - U
            //    E = U - E 
            // plus 5 comparison cases
            //    E == E
            //    E < E
            //    E <= E 
            //    E > E
            //    E >= E 
            // either E can be nullable 

            op = operation; 

            // parameters are easy -- they are the same as the type passed in
            expectedParameters = new ParameterInfo[2];
            expectedParameters[0] = new SimpleParameterInfo(lhs); 
            expectedParameters[1] = new SimpleParameterInfo(rhs);
 
            // compute return type (depends on type of operation) 
            // start by getting the types without Nullable<>
            bool lhsNullable = ConditionHelper.IsNullableValueType(lhs); 
            bool rhsNullable = ConditionHelper.IsNullableValueType(rhs);
            lhsBaseType = (lhsNullable) ? Nullable.GetUnderlyingType(lhs) : lhs;
            rhsBaseType = (rhsNullable) ? Nullable.GetUnderlyingType(rhs) : rhs;
            // determine the underlying types for both sides 
            if (lhsBaseType.IsEnum)
                lhsRootType = EnumHelper.GetUnderlyingType(lhsBaseType); 
            else 
                lhsRootType = lhsBaseType;
 
            if (rhsBaseType.IsEnum)
                rhsRootType = EnumHelper.GetUnderlyingType(rhsBaseType);
            else
                rhsRootType = rhsBaseType; 

            switch (op) 
            { 
                case CodeBinaryOperatorType.Add:
                    // add always produces an enum, except enum + enum 
                    if ((lhsBaseType.IsEnum) && (rhs.IsEnum))
                        resultBaseType = lhsRootType;
                    else if (lhsBaseType.IsEnum)
                        resultBaseType = lhsBaseType; 
                    else
                        resultBaseType = rhsBaseType; 
                    // if either side is nullable, result is nullable 
                    resultIsNullable = (lhsNullable || rhsNullable);
                    resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType; 
                    break;
                case CodeBinaryOperatorType.Subtract:
                    // subtract can be an enum or the underlying type
                    if (rhsBaseType.IsEnum && lhsBaseType.IsEnum) 
                    {
                        resultRootType = rhsRootType; 
                        resultBaseType = rhsRootType; 
                    }
                    else if (lhsBaseType.IsEnum) 
                    {
                        // special case for E - 0
                        // if 0 is the underlying type, then use E - U
                        // if not the underlying type, then 0 becomes E, use E - E 
                        resultRootType = lhsRootType;
                        if (isZero && rhsBaseType != lhsRootType) 
                            resultBaseType = lhsRootType; 
                        else
                            resultBaseType = lhsBaseType; 
                    }
                    else    // rhsType.IsEnum
                    {
                        // special case for 0 - E 
                        // in all cases 0 becomes E, use E - E
                        resultRootType = rhsRootType; 
                        if (isZero) 
                            resultBaseType = rhsRootType;
                        else 
                            resultBaseType = rhsBaseType;
                    }
                    resultIsNullable = (lhsNullable || rhsNullable);
                    resultType = (resultIsNullable) ? typeof(Nullable<>).MakeGenericType(resultBaseType) : resultBaseType; 
                    break;
                case CodeBinaryOperatorType.ValueEquality: 
                case CodeBinaryOperatorType.LessThan: 
                case CodeBinaryOperatorType.LessThanOrEqual:
                case CodeBinaryOperatorType.GreaterThan: 
                case CodeBinaryOperatorType.GreaterThanOrEqual:
                    resultType = typeof(bool);
                    break;
            } 
        }
 
        public override MethodInfo GetBaseDefinition() 
        {
            return null; 
        }

        public override ICustomAttributeProvider ReturnTypeCustomAttributes
        { 
            get { return null; }
        } 
 
        public override MethodAttributes Attributes
        { 
            get { return MethodAttributes.Static; }
        }

        public override MethodImplAttributes GetMethodImplementationFlags() 
        {
            return MethodImplAttributes.Runtime; 
        } 

        public override ParameterInfo[] GetParameters() 
        {
            return expectedParameters;
        }
 
        [SuppressMessage("Microsoft.Performance", "CA1803:AvoidCostlyCallsWherePossible")]
        public override object Invoke(object obj, BindingFlags invokeAttr, Binder binder, object[] parameters, CultureInfo culture) 
        { 
            // we should get passed in 2 values that correspond to the parameter types
 
            object result;
            ArithmeticLiteral leftArithmetic, rightArithmetic;
            Literal leftLiteral, rightLiteral;
 
            // for design-time types we couldn't find the underlying type, so do it now
            if (lhsRootType == null) 
                lhsRootType = Enum.GetUnderlyingType(lhsBaseType); 
            if (rhsRootType == null)
                rhsRootType = Enum.GetUnderlyingType(rhsBaseType); 

            switch (op)
            {
                case CodeBinaryOperatorType.Add: 
                    // if either is null, then the result is null
                    if ((parameters[0] == null) || (parameters[1] == null)) 
                        return null; 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(lhsRootType, parameters[0]);
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(rhsRootType, parameters[1]); 
                    result = leftArithmetic.Add(rightArithmetic);
                    result = Executor.AdjustType(result.GetType(), result, resultBaseType);
                    if (resultIsNullable)
                        result = Activator.CreateInstance(resultType, result); 
                    return result;
                case CodeBinaryOperatorType.Subtract: 
                    // if either is null, then the result is null 
                    if ((parameters[0] == null) || (parameters[1] == null))
                        return null; 
                    leftArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
                        Executor.AdjustType(lhsRootType, parameters[0], resultRootType));
                    rightArithmetic = ArithmeticLiteral.MakeLiteral(resultRootType,
                        Executor.AdjustType(rhsRootType, parameters[1], resultRootType)); 
                    result = leftArithmetic.Subtract(rightArithmetic);
                    result = Executor.AdjustType(result.GetType(), result, resultBaseType); 
                    if (resultIsNullable) 
                        result = Activator.CreateInstance(resultType, result);
                    return result; 

                case CodeBinaryOperatorType.ValueEquality:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]); 
                    return leftLiteral.Equal(rightLiteral);
                case CodeBinaryOperatorType.LessThan: 
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]); 
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.LessThan(rightLiteral); 
                case CodeBinaryOperatorType.LessThanOrEqual:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.LessThanOrEqual(rightLiteral); 
                case CodeBinaryOperatorType.GreaterThan:
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]); 
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]); 
                    return leftLiteral.GreaterThan(rightLiteral);
                case CodeBinaryOperatorType.GreaterThanOrEqual: 
                    leftLiteral = Literal.MakeLiteral(lhsRootType, parameters[0]);
                    rightLiteral = Literal.MakeLiteral(rhsRootType, parameters[1]);
                    return leftLiteral.GreaterThanOrEqual(rightLiteral);
            } 
            string message = string.Format(CultureInfo.CurrentCulture, Messages.BinaryOpNotSupported, op.ToString());
            throw new RuleEvaluationException(message); 
        } 

        public override RuntimeMethodHandle MethodHandle 
        {
            get { return new RuntimeMethodHandle(); }
        }
 
        public override Type DeclaringType
        { 
            get { return typeof(Enum); } 
        }
 
        public override object[] GetCustomAttributes(Type attributeType, bool inherit)
        {
            return new object[0];
        } 

        public override object[] GetCustomAttributes(bool inherit) 
        { 
            return new object[0];
        } 

        public override bool IsDefined(Type attributeType, bool inherit)
        {
            return true; 
        }
 
        public override string Name 
        {
            get { return "op_Enum"; } 
        }

        public override Type ReflectedType
        { 
            get { return resultType; }
        } 
 
        public override Type ReturnType
        { 
            get { return resultType; }
        }
    }
    #endregion 

    #region SimpleRunTimeTypeProvider 
 
    internal class SimpleRunTimeTypeProvider : ITypeProvider
    { 
        private Assembly root;
        private List references;

        internal SimpleRunTimeTypeProvider(Assembly startingAssembly) 
        {
            root = startingAssembly; 
        } 

        public Type GetType(string name) 
        {
            return GetType(name, false);
        }
 
        public Type GetType(string name, bool throwOnError)
        { 
            // is the type available in the main workflow assembly? 
            Type type = root.GetType(name, throwOnError, false);
            if (type != null) 
                return type;

            // now try mscorlib or this assembly
            // (or if the name is an assembly qualified name) 
            type = Type.GetType(name, throwOnError, false);
            if (type != null) 
                return type; 

            // no luck so far, so try all referenced assemblies 
            foreach (Assembly a in ReferencedAssemblies)
            {
                type = a.GetType(name, throwOnError, false);
                if (type != null) 
                    return type;
            } 
 
            // keep going by trying all loaded assemblies
            Assembly[] loaded = AppDomain.CurrentDomain.GetAssemblies(); 
            for (int i = 0; i < loaded.Length; ++i)
            {
                type = loaded[i].GetType(name, throwOnError, false);
                if (type != null) 
                    return type;
            } 
            return null; 
        }
 
        public Type[] GetTypes()
        {
            List types = new List();
            try 
            {
                types.AddRange(root.GetTypes()); 
            } 
            catch (ReflectionTypeLoadException e)
            { 
                // problems loading all the types, take what we can get
                foreach (Type type in e.Types)
                    if (type != null)
                        types.Add(type); 
            }
            foreach (Assembly a in ReferencedAssemblies) 
            { 
                try
                { 
                    types.AddRange(a.GetTypes());
                }
                catch (ReflectionTypeLoadException e)
                { 
                    // problems loading all the types, take what we can get
                    foreach (Type type in e.Types) 
                        if (type != null) 
                            types.Add(type);
                } 
            }
            return types.ToArray();
        }
 
        public Assembly LocalAssembly
        { 
            get { return root; } 
        }
 
        public ICollection ReferencedAssemblies
        {
            get
            { 
                // references is created on demand, does not include root
                if (references == null) 
                { 
                    List list = new List();
                    foreach (AssemblyName a in root.GetReferencedAssemblies()) 
                    {
                        list.Add(Assembly.Load(a));
                    }
                    references = list; 
                }
                return references; 
            } 
        }
 
        public IDictionary TypeLoadErrors
        {
            get
            { 
                // we never use this method, so add use of EventHandlers to keep compiler happy
                TypesChanged.Invoke(this, null); 
                TypeLoadErrorsChanged.Invoke(this, null); 
                return null;
            } 
        }

        public event EventHandler TypesChanged;
 
        public event EventHandler TypeLoadErrorsChanged;
    } 
    #endregion 

    #region RuleValidation 

    public class RuleValidation
    {
        private Type thisType; 
        private ITypeProvider typeProvider;
        private ValidationErrorCollection errors = new ValidationErrorCollection(); 
        private Dictionary typesUsed = new Dictionary(16); 
        private Dictionary typesUsedAuthorized;
        private Stack activeParentNodes = new Stack(); 
        private Dictionary expressionInfoMap = new Dictionary();
        private Dictionary typeRefMap = new Dictionary();
        private bool checkStaticType;
        private IList authorizedTypes; 
        private static readonly Type voidType = typeof(void);
        private static string voidTypeName = voidType.AssemblyQualifiedName; 
 
        #region Constructors
 
        // Validate at design time.
        public RuleValidation(Activity activity, ITypeProvider typeProvider, bool checkStaticType)
        {
            if (activity == null) 
                throw new ArgumentNullException("activity");
            if (typeProvider == null) 
                throw new ArgumentNullException("typeProvider"); 

            this.thisType = ConditionHelper.GetContextType(typeProvider, activity); 
            this.typeProvider = typeProvider;
            this.checkStaticType = checkStaticType;
            if (checkStaticType)
            { 
                Debug.Assert(WorkflowCompilationContext.Current != null, "Can't have checkTypes set to true without a context in scope");
                this.authorizedTypes = WorkflowCompilationContext.Current.GetAuthorizedTypes(); 
                this.typesUsedAuthorized = new Dictionary(); 
                this.typesUsedAuthorized.Add(voidTypeName, voidType);
            } 
        }

        // Validate at runtime when we have the actual subject instance.  This is
        // mostly for conditions used in activities like IfElse. 
        internal RuleValidation(object thisObject)
        { 
            if (thisObject == null) 
                throw new ArgumentNullException("thisObject");
 
            this.thisType = thisObject.GetType();
            this.typeProvider = new SimpleRunTimeTypeProvider(this.thisType.Assembly);
        }
 
        // Validate at runtime when we have just the type.  This is mostly for rules.
        public RuleValidation(Type thisType, ITypeProvider typeProvider) 
        { 
            if (thisType == null)
                throw new ArgumentNullException("thisType"); 

            this.thisType = thisType;
            this.typeProvider = (typeProvider != null) ? typeProvider : new SimpleRunTimeTypeProvider(this.thisType.Assembly);
        } 

        #endregion 
 
        #region Internal validation methods
 
        internal bool ValidateConditionExpression(CodeExpression expression)
        {
            if (expression == null)
                throw new ArgumentNullException("expression"); 

            // Run the validation pass. 
            RuleExpressionInfo exprInfo = RuleExpressionWalker.Validate(this, expression, false); 
            if (exprInfo == null)
                return false; 

            Type resultType = exprInfo.ExpressionType;
            if (!IsValidBooleanResult(resultType))
            { 
                // not a boolean, so complain unless another error may have caused this problem
                if (resultType != null || Errors.Count == 0) 
                { 
                    string message = Messages.ConditionMustBeBoolean;
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_ConditionMustBeBoolean); 
                    error.UserData[RuleUserDataKeys.ErrorObject] = expression;
                    Errors.Add(error);
                }
            } 

            return Errors.Count == 0; 
        } 

        internal static bool IsValidBooleanResult(Type type) 
        {
            return ((type == typeof(bool))
                || (type == typeof(bool?))
                || (ImplicitConversion(type, typeof(bool)))); 
        }
 
        internal static bool IsPrivate(MethodInfo methodInfo) 
        {
            return methodInfo.IsPrivate 
                || methodInfo.IsFamily
                || methodInfo.IsFamilyOrAssembly
                || methodInfo.IsFamilyAndAssembly;
        } 

        internal static bool IsPrivate(FieldInfo fieldInfo) 
        { 
            return fieldInfo.IsPrivate
                || fieldInfo.IsFamily 
                || fieldInfo.IsFamilyOrAssembly
                || fieldInfo.IsFamilyAndAssembly;
        }
 
        internal static bool IsInternal(MethodInfo methodInfo)
        { 
            return methodInfo.IsAssembly 
                || methodInfo.IsFamilyAndAssembly;
        } 

        internal static bool IsInternal(FieldInfo fieldInfo)
        {
            return fieldInfo.IsAssembly 
                || fieldInfo.IsFamilyAndAssembly;
        } 
 
        #endregion
 
        #region Miscellaneous public properties & methods

        public Type ThisType
        { 
            get { return thisType; }
        } 
 
        internal ITypeProvider GetTypeProvider()
        { 
            return typeProvider;
        }

        public ValidationErrorCollection Errors 
        {
            get { return errors; } 
        } 

        internal bool AllowInternalMembers(Type type) 
        {
            return type.Assembly == thisType.Assembly;
        }
 
        internal void AddError(ValidationError error)
        { 
            this.Errors.Add(error); 
        }
 
        public bool PushParentExpression(CodeExpression newParent)
        {
            if (newParent == null)
                throw new ArgumentNullException("newParent"); 

            if (activeParentNodes.Contains(newParent)) 
            { 
                string message = string.Format(CultureInfo.CurrentCulture, Messages.CyclicalExpression);
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CyclicalExpression); 
                error.UserData[RuleUserDataKeys.ErrorObject] = newParent;
                Errors.Add(error);
                return false;
            } 

            activeParentNodes.Push(newParent); 
            return true; 
        }
 
        public void PopParentExpression()
        {
            activeParentNodes.Pop();
        } 

        // Get the ExpressionInfo associated with a given CodeExpression 
        public RuleExpressionInfo ExpressionInfo(CodeExpression expression) 
        {
            if (expression == null) 
                throw new ArgumentNullException("expression");

            RuleExpressionInfo exprInfo = null;
            expressionInfoMap.TryGetValue(expression, out exprInfo); 

            return exprInfo; 
        } 

        #endregion 

        #region CodeDom Expression Validation methods

        internal RuleExpressionInfo ValidateSubexpression(CodeExpression expr, RuleExpressionInternal ruleExpr, bool isWritten) 
        {
            Debug.Assert(ruleExpr != null, "Validation::ValidateSubexpression - IRuleExpression is null"); 
            Debug.Assert(expr != null, "Validation::ValidateSubexpression - CodeExpression is null"); 

            RuleExpressionInfo exprInfo = ruleExpr.Validate(expr, this, isWritten); 

            if (exprInfo != null)
            {
                // Add the CodeExpression object to the info map.  We don't want to add the IRuleExpression guy 
                // as the key, since it might likely be just a tearoff wrapper.
                expressionInfoMap[expr] = exprInfo; 
            } 

            return exprInfo; 
        }

        internal static bool TypesAreAssignable(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error)
        { 
            // determine if rhsType can be implicitly converted to lhsType,
            // following the rules in C# specification section 6.1, 
            // plus support for Nullable 

            // all but 6.1.7 handled as a standard implicit conversion 
            if (StandardImplicitConversion(rhsType, lhsType, rhsExpression, out error))
                return true;
            if (error != null)
                return false; 

            // no standard implicit conversion works, see if user specified one 
            // from section 6.4.3, start by determining what types to check 
            // as we find each type, add the list of implicit conversions available
            if (FindImplicitConversion(rhsType, lhsType, out error) == null) 
                return false;
            return true;
        }
 
        internal static bool ExplicitConversionSpecified(Type fromType, Type toType, out ValidationError error)
        { 
            // determine if fromType can be implicitly converted to toType, 
            // following the rules in C# specification section 6.2
 
            // start by seeing if there is a standard implicit conversion
            if (StandardImplicitConversion(fromType, toType, null, out error))
                return true;
            if (error != null) 
                return false;
 
            // explicit numeric conversions 
            // also handles Enum conversions, since GetTypeCode returns the underlying type
            if (fromType.IsValueType && toType.IsValueType && IsExplicitNumericConversion(fromType, toType)) 
                return true;

            // explicit reference conversions
            // this looks like the inverse of implicit conversions 
            ValidationError dummyError;		// so we don't return an error
            if (StandardImplicitConversion(toType, fromType, null, out dummyError)) 
                return true; 
            // include interface checks
            if (toType.IsInterface) 
            {
                // from any class-type S to any interface-type T, provided S is not sealed and provided S does not implement T.
                // latter part should be handled by implicit conversion, so we are ok as long as class is not sealed
                if ((fromType.IsClass) && (!fromType.IsSealed)) 
                    return true;
                // from any interface-type S to any interface-type T, provided S is not derived from T. 
                // again, if S derived from T, handled by implicit conversion above 
                if (fromType.IsInterface)
                    return true; 
            }
            if (fromType.IsInterface)
            {
                // from any interface-type S to any class-type T, provided T is not sealed or provided T implements S. 
                if ((toType.IsClass) && ((!toType.IsSealed) || (InterfaceMatch(toType.GetInterfaces(), fromType))))
                    return true; 
            } 

            // no look for user-defined conversions 
            // from section 6.4.4, start by determining what types to check
            // as we find each type, add the list of implicit conversions available
            if (FindExplicitConversion(fromType, toType, out error) == null)
                return false; 
            return true;
        } 
 
        private static bool InterfaceMatch(Type[] types, Type fromType)
        { 
            foreach (Type t in types)
            {
                if (t == fromType)
                    return true; 
            }
            return false; 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        internal static MethodInfo FindImplicitConversion(Type fromType, Type toType, out ValidationError error)
        {
            List candidates = new List();
 
            bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
            bool toIsNullable = ConditionHelper.IsNullableValueType(toType); 
            Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType; 
            Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
 
            if (fromType0.IsClass)
            {
                AddImplicitConversions(fromType0, fromType, toType, candidates);
                Type baseType = fromType0.BaseType; 
                while ((baseType != null) && (baseType != typeof(object)))
                { 
                    AddImplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                } 
            }
            else if (IsStruct(fromType0))
            {
                AddImplicitConversions(fromType0, fromType, toType, candidates); 
            }
            if ((toType0.IsClass) || (IsStruct(toType0))) 
            { 
                AddImplicitConversions(toType0, fromType, toType, candidates);
            } 

            // if both types are nullable, add the lifted operators
            if (fromIsNullable && toIsNullable)
            { 
                // start by finding all the conversion operators from S0 -> T0
                List liftedCandidates = new List(); 
                if (fromType0.IsClass) 
                {
                    AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates); 
                    Type baseType = fromType0.BaseType;
                    while ((baseType != null) && (baseType != typeof(object)))
                    {
                        AddImplicitConversions(baseType, fromType0, toType0, liftedCandidates); 
                        baseType = baseType.BaseType;
                    } 
                } 
                else if (IsStruct(fromType0))
                { 
                    AddImplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
                }
                if ((toType0.IsClass) || (IsStruct(toType0)))
                { 
                    AddImplicitConversions(toType0, fromType0, toType0, liftedCandidates);
                } 
 
                // add them all to the candidates list as lifted methods (which wraps them appropriately)
                foreach (MethodInfo mi in liftedCandidates) 
                {
                    // only lift candidates that convert from a non-nullable value type
                    // to a non-nullable value type
                    ParameterInfo[] parameters = mi.GetParameters(); 
                    if (ConditionHelper.IsNonNullableValueType(mi.ReturnType) && ConditionHelper.IsNonNullableValueType(parameters[0].ParameterType))
                        candidates.Add(new LiftedConversionMethodInfo(mi)); 
                } 
            }
 
            if (candidates.Count == 0)
            {
                // no overrides, so must be false
                string message = string.Format(CultureInfo.CurrentCulture, 
                    Messages.NoConversion,
                    RuleDecompiler.DecompileType(fromType), 
                    RuleDecompiler.DecompileType(toType)); 
                error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                return null; 
            }

            // find the most specific source type
            ValidationError dummyError;		// so we don't return an error 
            Type sx = candidates[0].GetParameters()[0].ParameterType;
            if (sx != fromType) 
            { 
                for (int i = 1; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (testType == fromType)
                    {
                        // we have a match with the source type, so that's the correct answer 
                        sx = fromType;
                        break; 
                    } 
                    if (StandardImplicitConversion(testType, sx, null, out dummyError))
                        sx = testType; 
                }
            }

            // find the most specific target type 
            Type tx = candidates[0].ReturnType;
            if (tx != toType) 
            { 
                for (int i = 1; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].ReturnType;
                    if (testType == toType)
                    {
                        // we have a match with the target type, so that's the correct answer 
                        tx = toType;
                        break; 
                    } 
                    if (StandardImplicitConversion(tx, testType, null, out dummyError))
                        tx = testType; 
                }
            }

            // see how many candidates convert from sx to tx, ignoring lifted methods 
            int numMatches = 0;
            int position = 0; 
            for (int i = 0; i < candidates.Count; ++i) 
            {
                if ((candidates[i].ReturnType == tx) && 
                    (candidates[i].GetParameters()[0].ParameterType == sx) &&
                    (!(candidates[i] is LiftedConversionMethodInfo)))
                {
                    position = i; 
                    ++numMatches;
                } 
            } 
            if (numMatches == 1)
            { 
                // found what we are looking for
                error = null;
                return candidates[position];
            } 

            // now check for lifted conversions 
            if ((toIsNullable) && (numMatches == 0)) 
            {
                if (fromIsNullable) 
                {
                    for (int i = 0; i < candidates.Count; ++i)
                    {
                        if ((candidates[i].ReturnType == tx) && 
                            (candidates[i].GetParameters()[0].ParameterType == sx) &&
                            (candidates[i] is LiftedConversionMethodInfo)) 
                        { 
                            position = i;
                            ++numMatches; 
                        }
                    }
                    if (numMatches == 1)
                    { 
                        // found what we are looking for
                        error = null; 
                        return candidates[position]; 
                    }
                } 
                else
                {
                    // we are doing a conversion T? = S, so a conversion from S -> T is valid
                    MethodInfo result = FindImplicitConversion(fromType, toType0, out error); 
                    if (result != null)
                    { 
                        error = null; 
                        // return it as a lifted method so the wrapping to T? is done
                        return new LiftedConversionMethodInfo(result); 
                    }
                }
            }
 
            // no exact matches, so it's an error
            string message2 = string.Format(CultureInfo.CurrentCulture, 
                Messages.AmbiguousConversion, 
                RuleDecompiler.DecompileType(fromType),
                RuleDecompiler.DecompileType(toType)); 
            error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible);
            return null;
        }
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal static MethodInfo FindExplicitConversion(Type fromType, Type toType, out ValidationError error) 
        { 
            List candidates = new List();
            ValidationError dummyError;		// don't return transient errors 

            bool fromIsNullable = ConditionHelper.IsNullableValueType(fromType);
            bool toIsNullable = ConditionHelper.IsNullableValueType(toType);
            Type fromType0 = (fromIsNullable) ? Nullable.GetUnderlyingType(fromType) : fromType; 
            Type toType0 = (toIsNullable) ? Nullable.GetUnderlyingType(toType) : toType;
 
            if (fromType0.IsClass) 
            {
                AddExplicitConversions(fromType0, fromType, toType, candidates); 
                Type baseType = fromType0.BaseType;
                while ((baseType != null) && (baseType != typeof(object)))
                {
                    AddExplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                } 
            } 
            else if (IsStruct(fromType0))
            { 
                AddExplicitConversions(fromType0, fromType, toType, candidates);
            }
            if (toType0.IsClass)
            { 
                AddExplicitConversions(toType0, fromType, toType, candidates);
                Type baseType = toType0.BaseType; 
                while ((baseType != null) && (baseType != typeof(object))) 
                {
                    AddExplicitConversions(baseType, fromType, toType, candidates); 
                    baseType = baseType.BaseType;
                }
            }
            else if (IsStruct(toType0)) 
            {
                AddExplicitConversions(toType0, fromType, toType, candidates); 
            } 

            // if both types are nullable, add the lifted operators 
            if (fromIsNullable && toIsNullable)
            {
                // start by finding all the conversion operators from S0 -> T0
                List liftedCandidates = new List(); 
                if (fromType0.IsClass)
                { 
                    AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates); 
                    Type baseType = fromType0.BaseType;
                    while ((baseType != null) && (baseType != typeof(object))) 
                    {
                        AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates);
                        baseType = baseType.BaseType;
                    } 
                }
                else if (IsStruct(fromType0)) 
                { 
                    AddExplicitConversions(fromType0, fromType0, toType0, liftedCandidates);
                } 
                if (toType0.IsClass)
                {
                    AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates);
                    Type baseType = toType0.BaseType; 
                    while ((baseType != null) && (baseType != typeof(object)))
                    { 
                        AddExplicitConversions(baseType, fromType0, toType0, liftedCandidates); 
                        baseType = baseType.BaseType;
                    } 
                }
                else if (IsStruct(toType0))
                {
                    AddExplicitConversions(toType0, fromType0, toType0, liftedCandidates); 
                }
 
                // add them all to the candidates list as lifted methods (which wraps them appropriately) 
                foreach (MethodInfo mi in liftedCandidates)
                    candidates.Add(new LiftedConversionMethodInfo(mi)); 
            }

            if (candidates.Count == 0)
            { 
                // no overrides, so must be false
                string message = string.Format(CultureInfo.CurrentCulture, 
                    Messages.NoConversion, 
                    RuleDecompiler.DecompileType(fromType),
                    RuleDecompiler.DecompileType(toType)); 
                error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible);
                return null;
            }
 
            // find the most specific source type
            // if any are s, s is the answer 
            Type sx = null; 
            for (int i = 0; i < candidates.Count; ++i)
            { 
                Type testType = candidates[i].GetParameters()[0].ParameterType;
                if (testType == fromType)
                {
                    // we have a match with the source type, so that's the correct answer 
                    sx = fromType;
                    break; 
                } 
            }
            // if no match, find the most encompassed type if the type encompasses s 
            if (sx == null)
            {
                for (int i = 0; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (StandardImplicitConversion(fromType, testType, null, out dummyError)) 
                    { 
                        if (sx == null)
                            sx = testType; 
                        else if (StandardImplicitConversion(testType, sx, null, out dummyError))
                            sx = testType;
                    }
                } 
            }
            // still no match, find most encompassing type 
            if (sx == null) 
            {
                for (int i = 0; i < candidates.Count; ++i) 
                {
                    Type testType = candidates[i].GetParameters()[0].ParameterType;
                    if (StandardImplicitConversion(testType, fromType, null, out dummyError))
                    { 
                        if (sx == null)
                            sx = testType; 
                        else if (StandardImplicitConversion(sx, testType, null, out dummyError)) 
                            sx = testType;
                    } 
                }
            }

            // find the most specific target type 
            // if any are t, t is the answer
            Type tx = null; 
            for (int i = 0; i < candidates.Count; ++i) 
            {
                Type testType = candidates[i].ReturnType; 
                if (testType == toType)
                {
                    // we have a match with the target type, so that's the correct answer
                    tx = toType; 
                    break;
                } 
            } 
            // if no match, find the most encompassed type if the type encompasses s
            if (tx == null) 
            {
                for (int i = 0; i < candidates.Count; ++i)
                {
                    Type testType = candidates[i].ReturnType; 
                    if (StandardImplicitConversion(testType, toType, null, out dummyError))
                    { 
                        if (tx == null) 
                            tx = testType;
                        else if (StandardImplicitConversion(tx, testType, null, out dummyError)) 
                            tx = testType;
                    }
                }
            } 
            // still no match, find most encompassing type
            if (tx == null) 
            { 
                for (int i = 0; i < candidates.Count; ++i)
                { 
                    Type testType = candidates[i].ReturnType;
                    if (StandardImplicitConversion(toType, testType, null, out dummyError))
                    {
                        if (tx == null) 
                            tx = testType;
                        else if (StandardImplicitConversion(testType, tx, null, out dummyError)) 
                            tx = testType; 
                    }
                } 
            }

            // see how many candidates convert from sx to tx, ignoring lifted methods
            int numMatches = 0; 
            int position = 0;
            for (int i = 0; i < candidates.Count; ++i) 
            { 
                if ((candidates[i].ReturnType == tx) &&
                        (candidates[i].GetParameters()[0].ParameterType == sx) && 
                        (!(candidates[i] is LiftedConversionMethodInfo)))
                {
                    position = i;
                    ++numMatches; 
                }
            } 
            if (numMatches == 1) 
            {
                // found what we are looking for 
                error = null;
                return candidates[position];
            }
 
            // now check for lifted conversions
            if ((toIsNullable) && (numMatches == 0)) 
            { 
                if (fromIsNullable)
                { 
                    for (int i = 0; i < candidates.Count; ++i)
                    {
                        if ((candidates[i].ReturnType == tx) &&
                            (candidates[i].GetParameters()[0].ParameterType == sx) && 
                            (candidates[i] is LiftedConversionMethodInfo))
                        { 
                            position = i; 
                            ++numMatches;
                        } 
                    }
                    if (numMatches == 1)
                    {
                        // found what we are looking for 
                        error = null;
                        return candidates[position]; 
                    } 
                }
                else 
                {
                    // we are doing a conversion T? = S, so a conversion from S -> T is valid
                    MethodInfo result = FindExplicitConversion(fromType, toType0, out error);
                    if (result != null) 
                    {
                        error = null; 
                        // return it as a lifted method so the wrapping to T? is done 
                        return new LiftedConversionMethodInfo(result);
                    } 
                }
            }

            // no exact matches, so it's an error 
            string message2 = string.Format(CultureInfo.CurrentCulture,
                Messages.AmbiguousConversion, 
                RuleDecompiler.DecompileType(fromType), 
                RuleDecompiler.DecompileType(toType));
            error = new ValidationError(message2, ErrorNumbers.Error_OperandTypesIncompatible); 
            return null;
        }

        private static bool IsStruct(Type type) 
        {
            return ((type.IsValueType) && (!type.IsPrimitive)); 
        } 

        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")] 
        private static bool IsExplicitNumericConversion(Type sourceType, Type testType)
        {
            // includes the implicit conversions as well
 
            // unwrap nullables
            TypeCode sourceTypeCode = (ConditionHelper.IsNullableValueType(sourceType)) 
                ? Type.GetTypeCode(sourceType.GetGenericArguments()[0]) 
                : Type.GetTypeCode(sourceType);
            TypeCode testTypeCode = (ConditionHelper.IsNullableValueType(testType)) 
                ? Type.GetTypeCode(testType.GetGenericArguments()[0])
                : Type.GetTypeCode(testType);

            switch (sourceTypeCode) 
            {
                case TypeCode.SByte: 
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.UInt16:
                        case TypeCode.UInt32:
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
 
                        case TypeCode.Int16: 
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true; 
                    }
                    return false; 
 
                case TypeCode.Byte:
                    switch (testTypeCode) 
                    {
                        case TypeCode.Byte:
                        case TypeCode.SByte:
                        case TypeCode.Char: 

                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    } 
                    return false;
 
                case TypeCode.Int16:
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.UInt16: 
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64:
                        case TypeCode.Char: 

                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false;

                case TypeCode.UInt16:
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Char:

                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    }
                    return false;
 
                case TypeCode.Int32:
                    switch (testTypeCode) 
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
 
                        case TypeCode.Int64:
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                            return true;
                    } 
                    return false;
 
                case TypeCode.UInt32: 
                    switch (testTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Char: 

                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false; 

                case TypeCode.Int64: 
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Char:

                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true; 
                    }
                    return false; 

                case TypeCode.UInt64:
                    switch (testTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 

                        case TypeCode.Single: 
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    }
                    return false;

                case TypeCode.Char: 
                    switch (testTypeCode)
                    { 
                        case TypeCode.Char: 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:

                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64: 
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true;
                    }
                    return false; 

                case TypeCode.Single: 
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16:
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                        case TypeCode.Single: 
                        case TypeCode.Decimal:

                        case TypeCode.Double:
                            return true; 
                    }
                    return false; 
 
                case TypeCode.Double:
                    switch (testTypeCode) 
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal: 
                            return true;
                    } 
                    return false; 

                case TypeCode.Decimal: 
                    switch (testTypeCode)
                    {
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64: 
                        case TypeCode.UInt64:
                        case TypeCode.Char:
                        case TypeCode.Single:
                        case TypeCode.Double: 
                        case TypeCode.Decimal:
                            return true; 
                    } 
                    return false;
            } 
            return false;
        }

 
        internal static bool ImplicitConversion(Type fromType, Type toType)
        { 
            ValidationError error; 

            // is there a standard conversion we can use 
            if (StandardImplicitConversion(fromType, toType, null, out error))
                return true;

            // no standard one, did the user provide one? 
            return (FindImplicitConversion(fromType, toType, out error) != null);
        } 
 
        [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
        internal static bool StandardImplicitConversion(Type rhsType, Type lhsType, CodeExpression rhsExpression, out ValidationError error) 
        {
            error = null;

            // 6.1.1 identity conversion 
            if (rhsType == lhsType)
            { 
                // Easy special case... they're the same type. 
                return true;
            } 

            // 6.1.4 (h) from the null type to any reference-type
            if (rhsType == typeof(NullLiteral))
            { 
                // Special case if the RHS is 'null'; just make sure the LHS type can be assigned a null value.
                if (ConditionHelper.IsNonNullableValueType(lhsType)) 
                { 
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.AssignNotAllowed, Messages.NullValue, RuleDecompiler.DecompileType(lhsType));
                    error = new ValidationError(message, ErrorNumbers.Error_OperandTypesIncompatible); 
                    return false;
                }
                return true;
            } 

            // check for nullables 
            bool lhsIsNullable = ConditionHelper.IsNullableValueType(lhsType); 
            bool rhsIsNullable = ConditionHelper.IsNullableValueType(rhsType);
            if (rhsIsNullable) 
            {
                if (!lhsIsNullable)
                {
                    // We had T1 = T2?, which is not valid for any T1 or T2, unless T1 is object 
                    return (lhsType == typeof(object));
                } 
 
                rhsType = Nullable.GetUnderlyingType(rhsType);
            } 

            if (lhsIsNullable)
                lhsType = Nullable.GetUnderlyingType(lhsType);
 
            if (lhsType == rhsType)
            { 
                // We had T? = T, which is valid. 
                return true;
            } 

            // handle rest of 6.1.4
            if (TypeProvider.IsAssignable(lhsType, rhsType))
            { 
                // They are assignable, which will handle inheritance and trivial up-casting.
                return true; 
            } 

            // 6.1.3 implicit enumeration conversions 
            if (lhsType.IsEnum)
            {
                // right-hand side can be decimal-integer-literal 0
                CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression; 
                if ((primitive == null) || (primitive.Value == null))
                { 
                    // not a constant 
                    return false;
                } 
                switch (Type.GetTypeCode(primitive.Value.GetType()))
                {
                    case TypeCode.SByte:
                        return ((sbyte)primitive.Value == 0); 
                    case TypeCode.Byte:
                        return ((byte)primitive.Value == 0); 
                    case TypeCode.Int16: 
                        return ((short)primitive.Value == 0);
                    case TypeCode.UInt16: 
                        return ((ushort)primitive.Value == 0);
                    case TypeCode.Int32:
                        return ((int)primitive.Value == 0);
                    case TypeCode.UInt32: 
                        return ((uint)primitive.Value == 0);
                    case TypeCode.Int64: 
                        return ((long)primitive.Value == 0); 
                    case TypeCode.UInt64:
                        return ((ulong)primitive.Value == 0); 
                    case TypeCode.Char:
                        return ((char)primitive.Value == 0);
                }
                return false; 
            }
            if (rhsType.IsEnum) 
            { 
                // don't treat enums as numbers
                return false; 
            }

            // 6.1.2 implicit numeric conversions
            // 6.1.6 implicit constant expression conversions 
            // not assignable, but the assignment might still be valid for
            // value types if a free conversion is available. 
            TypeCode lhsTypeCode = Type.GetTypeCode(lhsType); 
            TypeCode rhsTypeCode = Type.GetTypeCode(rhsType);
 
            switch (lhsTypeCode)
            {
                case TypeCode.Decimal:
                    switch (rhsTypeCode) 
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                        case TypeCode.Decimal:
                        case TypeCode.Char: 
                            return true; 
                    }
                    return false; 

                case TypeCode.Double:
                    switch (rhsTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single: 
                        case TypeCode.Double:
                        case TypeCode.Char: 
                            return true; 
                    }
                    return false; 

                case TypeCode.Single:
                    switch (rhsTypeCode)
                    { 
                        case TypeCode.SByte:
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Single: 
                        case TypeCode.Char:
                            return true; 
                    } 
                    return false;
 
                case TypeCode.Char:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Byte: 
                        case TypeCode.Int16:
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.SByte:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                            return true;
                        case TypeCode.Byte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Byte:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Int16: 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int16:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                            return true; 
                        case TypeCode.UInt16:
                        case TypeCode.Int32: 
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64:
                        case TypeCode.Char: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int32:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.Int64:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.SByte: 
                        case TypeCode.Byte:
                        case TypeCode.Int16: 
                        case TypeCode.UInt16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32: 
                        case TypeCode.Int64:
                        case TypeCode.Char:
                            return true;
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt16:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.Char: 
                            return true; 
                        case TypeCode.SByte:
                        case TypeCode.Int16: 
                        case TypeCode.Int32:
                        case TypeCode.UInt32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt32:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.UInt32: 
                        case TypeCode.Char: 
                            return true;
                        case TypeCode.SByte: 
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.UInt64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                case TypeCode.UInt64:
                    switch (rhsTypeCode)
                    {
                        case TypeCode.Byte: 
                        case TypeCode.UInt16:
                        case TypeCode.UInt32: 
                        case TypeCode.UInt64: 
                        case TypeCode.Char:
                            return true; 
                        case TypeCode.SByte:
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64: 
                            // Maybe, if the value is in range.
                            return CheckValueRange(rhsExpression, lhsType, out error); 
                    } 
                    return false;
 
                default:
                    // It wasn't a numeric type, it was some other kind of value type (e.g., bool,
                    // DateTime, etc).  There will be no conversions.
                    return false; 
            }
        } 
 
        private static void AddImplicitConversions(Type t, Type source, Type target, List methods)
        { 
            // append the list of methods that match the name specified
            // s is the source type, so the parameter must encompass it
            // t is the target type, so it must encompass the result
            MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public); 
            foreach (MethodInfo mi in possible)
            { 
                if ((mi.Name == "op_Implicit") && (mi.GetParameters().Length == 1)) 
                {
                    Type sourceType = mi.GetParameters()[0].ParameterType; 
                    Type targetType = mi.ReturnType;
                    ValidationError error;
                    if (StandardImplicitConversion(source, sourceType, null, out error) &&
                        StandardImplicitConversion(targetType, target, null, out error)) 
                    {
                        if (!methods.Contains(mi)) 
                            methods.Add(mi); 
                    }
                } 
            }
        }

        private static void AddExplicitConversions(Type t, Type source, Type target, List methods) 
        {
            // append the list of methods that match the name specified 
            // s is the source type, so the parameter must encompass it 
            // t is the target type, so it must encompass the result
            MethodInfo[] possible = t.GetMethods(BindingFlags.Static | BindingFlags.Public); 
            foreach (MethodInfo mi in possible)
            {
                if (((mi.Name == "op_Implicit") || (mi.Name == "op_Explicit")) && (mi.GetParameters().Length == 1))
                { 
                    Type sourceType = mi.GetParameters()[0].ParameterType;
                    Type targetType = mi.ReturnType; 
                    ValidationError error; 
                    if ((StandardImplicitConversion(source, sourceType, null, out error) || StandardImplicitConversion(sourceType, source, null, out error))
                     && (StandardImplicitConversion(target, targetType, null, out error) || StandardImplicitConversion(targetType, target, null, out error))) 
                    {
                        if (!methods.Contains(mi))
                            methods.Add(mi);
                    } 
                }
            } 
        } 

        [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] 
        private static bool CheckValueRange(CodeExpression rhsExpression, Type lhsType, out ValidationError error)
        {
            error = null;
 
            CodePrimitiveExpression primitive = rhsExpression as CodePrimitiveExpression;
            if (primitive != null) 
            { 
                try
                { 
                    System.Convert.ChangeType(primitive.Value, lhsType, CultureInfo.CurrentCulture);
                    // If we get here without throwing, it's valid.
                    return true;
                } 
                catch (Exception e)
                { 
                    error = new ValidationError(e.Message, ErrorNumbers.Error_OperandTypesIncompatible); 
                    return false;
                } 
            }

            return false;
        } 

        internal bool ValidateMemberAccess( 
            CodeExpression targetExpression, Type targetType, FieldInfo accessorMethod, string memberName, CodeExpression parentExpr) 
        {
            return this.ValidateMemberAccess( 
                targetExpression, targetType, memberName, parentExpr,
                accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
        }
 
        internal bool ValidateMemberAccess(
            CodeExpression targetExpression, Type targetType, MethodInfo accessorMethod, string memberName, CodeExpression parentExpr) 
        { 
            return this.ValidateMemberAccess(
                targetExpression, targetType, memberName, parentExpr, 
                accessorMethod.DeclaringType.Assembly, RuleValidation.IsPrivate(accessorMethod), RuleValidation.IsInternal(accessorMethod), accessorMethod.IsStatic);
        }

        private bool ValidateMemberAccess( 
            CodeExpression targetExpression, Type targetType, string memberName, CodeExpression parentExpr,
            Assembly methodAssembly, bool isPrivate, bool isInternal, bool isStatic) 
        { 
            string message;
 
            if (isStatic != (targetExpression is CodeTypeReferenceExpression))
            {
                // If it's static, then the target object must be a type ref, and vice versa.
 
                int errorNumber;
 
                if (isStatic) 
                {
                    // We have "object.StaticMember" 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.StaticMember, memberName);
                    errorNumber = ErrorNumbers.Error_StaticMember;
                }
                else 
                {
                    // We have "TypeName.NonStaticMember" 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.NonStaticMember, memberName); 
                    errorNumber = ErrorNumbers.Error_NonStaticMember;
                } 

                ValidationError error = new ValidationError(message, errorNumber);
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
                Errors.Add(error); 

                return false; 
            } 

            if (isPrivate && targetType != ThisType) 
            {
                // Can't access private members except on the subject type.
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessPrivateMember, memberName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr;
                Errors.Add(error); 
 
                return false;
            } 

            if (isInternal && ThisType.Assembly != methodAssembly)
            {
                // Can't access internal members except on the subject assembly. 
                message = string.Format(CultureInfo.CurrentCulture, Messages.CannotAccessInternalMember, memberName, RuleDecompiler.DecompileType(targetType));
                ValidationError error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                error.UserData[RuleUserDataKeys.ErrorObject] = parentExpr; 
                Errors.Add(error);
 
                return false;
            }

            return true; 
        }
 
        #region Field and property resolution 

        internal MemberInfo ResolveFieldOrProperty(Type targetType, string name) 
        {
            BindingFlags bindingFlags = BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy;
            if (AllowInternalMembers(targetType))
                bindingFlags |= BindingFlags.NonPublic; 

            // Look up a field or property of the given name. 
            MemberInfo[] results = targetType.GetMember(name, MemberTypes.Field | MemberTypes.Property, bindingFlags); 

            if (results != null) 
            {
                int numResults = results.Length;
                if (numResults == 1)
                { 
                    // If we found exactly one, we're good.
                    return results[0]; 
                } 
                else if (numResults > 1)
                { 
                    // We may have found more than one property if it's overloaded.  If we find one without
                    // any parameters, return that one.
                    for (int i = 0; i < numResults; ++i)
                    { 
                        MemberInfo member = results[i];
                        System.Diagnostics.Debug.Assert(member.MemberType == MemberTypes.Property, "only properties can be overloaded"); 
 
                        PropertyInfo pi = (PropertyInfo)member;
                        ParameterInfo[] parms = pi.GetIndexParameters(); 
                        if (parms == null || parms.Length == 0)
                        {
                            if (pi != null)
                            { 
                                IsAuthorized(pi.PropertyType);
                            } 
                            return pi; 
                        }
                    } 
                }
            }

            // If we didn't find it, and if the target type is an interface, try resolving a property 
            // that may exist in its inheritance chain.  (Fields cannot appear on interfaces.)
            if (targetType.IsInterface) 
                return ResolveProperty(targetType, name, bindingFlags); 

            // Otherwise, it's no good. 
            return null;
        }

        internal PropertyInfo ResolveProperty(Type targetType, string propertyName, BindingFlags bindingFlags) 
        {
 
            PropertyInfo pi = GetProperty(targetType, propertyName, bindingFlags); 
            if (pi == null && targetType.IsInterface)
            { 
                Type[] parentInterfacesArray = targetType.GetInterfaces();
                List parentInterfaces = new List();
                parentInterfaces.AddRange(parentInterfacesArray);
 
                int index = 0;
                while (index < parentInterfaces.Count) 
                { 
                    pi = GetProperty(parentInterfaces[index], propertyName, bindingFlags);
                    if (pi != null) 
                        break;

                    Type[] pInterfaces = parentInterfaces[index].GetInterfaces();
                    if (pInterfaces.Length > 0) 
                        parentInterfaces.AddRange(pInterfaces);
                    ++index; 
                } 
            }
 
            if (pi != null)
            {
                IsAuthorized(pi.PropertyType);
            } 
            return pi;
        } 
 
        private static PropertyInfo GetProperty(Type targetType, string propertyName, BindingFlags bindingFlags)
        { 
            // Properties may be overloaded (in VB), so we have to ---- out those that we can support,
            // i.e., those that have no parameters.

            MemberInfo[] members = targetType.GetMember(propertyName, MemberTypes.Property, bindingFlags); 
            for (int m = 0; m < members.Length; ++m)
            { 
                PropertyInfo pi = (PropertyInfo)members[m]; 

                ParameterInfo[] parms = pi.GetIndexParameters(); 
                if (parms == null || parms.Length == 0)
                    return pi;
            }
 
            return null;
        } 
 
        #endregion
 
        #region Method resolution

        private class Argument
        { 
            internal CodeExpression expression;
            internal FieldDirection direction; 
            internal Type type; 

            internal Argument(CodeExpression expr, RuleValidation validation) 
            {
                this.expression = expr;

                this.direction = FieldDirection.In; 
                CodeDirectionExpression directionExpr = expr as CodeDirectionExpression;
                if (directionExpr != null) 
                    this.direction = directionExpr.Direction; 

                this.type = validation.ExpressionInfo(expr).ExpressionType; 
            }

            internal Argument(Type type)
            { 
                this.direction = FieldDirection.In;
                this.type = type; 
            } 
        }
 
        private class CandidateParameter
        {
            private Type type;
            private FieldDirection direction; 

            internal CandidateParameter(Type type) 
            { 
                this.type = type;
                this.direction = FieldDirection.In; 
            }

            internal CandidateParameter(ParameterInfo paramInfo)
            { 
                this.direction = FieldDirection.In;
                if (paramInfo.IsOut) 
                    this.direction = FieldDirection.Out; 
                else if (paramInfo.ParameterType.IsByRef)
                    this.direction = FieldDirection.Ref; 

                this.type = paramInfo.ParameterType;
            }
 
            internal bool Match(Argument argument, string methodName, int argPosition, out ValidationError error)
            { 
                string message; 

                // If we don't agree on the argument direction, this method is not a candidate. 
                if (this.direction != argument.direction)
                {
                    string dirString = "";
                    switch (this.direction) 
                    {
                        case FieldDirection.In: 
                            dirString = "in"; // No localization required, this is a keyword. 
                            break;
                        case FieldDirection.Out: 
                            dirString = "out"; // No localization required, this is a keyword.
                            break;
                        case FieldDirection.Ref:
                            dirString = "ref"; // No localization required, this is a keyword. 
                            break;
                    } 
 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.MethodDirectionMismatch, argPosition, methodName, dirString);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodDirectionMismatch); 

                    return false;
                }
 
                if (this.type.IsByRef && this.type != argument.type)
                { 
                    // If the parameter is "ref" or "out", then the types must match exactly. 
                    // If not, this method can't be a candidate.
 
                    message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type));
                    error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);

                    return false; 
                }
 
                // If the argument type is not assignable to the corresponding parameter type, 
                // this method can't be a candidate.
                if (!RuleValidation.TypesAreAssignable(argument.type, this.type, argument.expression, out error)) 
                {
                    if (error == null)
                    {
                        message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgumentTypeMismatch, argPosition, methodName, RuleDecompiler.DecompileType(argument.type), RuleDecompiler.DecompileType(this.type)); 
                        error = new ValidationError(message, ErrorNumbers.Error_MethodArgumentTypeMismatch);
                    } 
                    return false; 
                }
 
                // If we passed the above checks, this argument is a candidate match for the parameter.
                return true;
            }
 
            public override bool Equals(object obj)
            { 
                CandidateParameter otherParam = obj as CandidateParameter; 
                if (otherParam == null)
                    return false; 

                return this.direction == otherParam.direction && this.type == otherParam.type;
            }
 
            public override int GetHashCode()
            { 
                return this.direction.GetHashCode() ^ this.type.GetHashCode(); 
            }
 
            internal int CompareConversion(CandidateParameter otherParam, Argument argument)
            {
                // Return 0 if they are equal; 1 if this is better; -1 if this is worse.
                // This follows the C# specification 7.4.2.3 
                int better = 1;
                int worse = -1; 
                int equal = 0; 

                // If the two candidate parameters have the same type, neither one is better. 
                if (this.type == otherParam.type)
                    return equal;

                // If the argument type is the same as one of the parameter types, that parameter is better. 
                if (argument.type == this.type)
                    return better; 
                if (argument.type == otherParam.type) 
                    return worse;
 
                // If this parameter can be converted to the other parameter, and not vice versa, then
                // this is a better conversion.  (And in the reverse situation, it's a worse conversion.)
                ValidationError dummy;
                bool thisConvertsToOther = RuleValidation.TypesAreAssignable(this.type, otherParam.type, null, out dummy); 
                bool otherConvertsToThis = RuleValidation.TypesAreAssignable(otherParam.type, this.type, null, out dummy);
                if (thisConvertsToOther && !otherConvertsToThis) 
                    return better; 
                if (otherConvertsToThis && !thisConvertsToOther)
                    return worse; 

                // See if one is a better sign-preserving conversion than the other.
                if (BetterSignedConversion(this.type, otherParam.type))
                    return better; 
                if (BetterSignedConversion(otherParam.type, this.type))
                    return worse; 
 
                // Otherwise, neither conversion is better.
                return equal; 
            }

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
            private static bool BetterSignedConversion(Type t1, Type t2) 
            {
                TypeCode tc1 = Type.GetTypeCode(t1); 
                TypeCode tc2 = Type.GetTypeCode(t2); 

                switch (tc1) 
                {
                    case TypeCode.SByte:
                        switch (tc2)
                        { 
                            case TypeCode.Byte:
                            case TypeCode.UInt16: 
                            case TypeCode.UInt32: 
                            case TypeCode.UInt64:
                                // A conversion to sbyte is better than a conversion to an unsigned type. 
                                return true;
                        }
                        break;
 
                    case TypeCode.Int16:
                        switch (tc2) 
                        { 
                            case TypeCode.UInt16:
                            case TypeCode.UInt32: 
                            case TypeCode.UInt64:
                                // A conversion to short is better than a conversion to an unsigned type.
                                return true;
                        } 
                        break;
 
                    case TypeCode.Int32: 
                        if (tc2 == TypeCode.UInt32 || tc2 == TypeCode.UInt64)
                        { 
                            // A conversion to int is better than a conversion to an unsigned type.
                            return true;
                        }
                        break; 

                    case TypeCode.Int64: 
                        if (tc2 == TypeCode.UInt64) 
                        {
                            // A conversion to long is better than a conversion to an unsigned type. 
                            return true;
                        }
                        break;
 
                    case TypeCode.Object:
                        // it is possible that the types are nullable 
                        if (ConditionHelper.IsNullableValueType(t1)) 
                        {
                            t1 = t1.GetGenericArguments()[0]; 
                            // t2 may already be a value type
                            if (ConditionHelper.IsNullableValueType(t2))
                                t2 = t2.GetGenericArguments()[0];
                            return BetterSignedConversion(t1, t2); 
                        }
                        return false; 
                } 

                return false; 
            }
        }

        private class CandidateMember 
        {
            internal enum Form 
            { 
                Normal,     // no "params" expansion
                Expanded    // matched only after "params" expansion 
            }

            internal MemberInfo Member;
            private ParameterInfo[] memberParameters; 
            private List signature;
            private Form form; 
            private static ParameterInfo[] noParameters = new ParameterInfo[0]; 
            private static List noSignature = new List();
 
            // Constructor for candidate methods with parameters.
            internal CandidateMember(MemberInfo member, ParameterInfo[] parameters, List signature, Form form)
            {
                this.Member = member; 
                this.memberParameters = parameters;
                this.signature = signature; 
                this.form = form; 
            }
 
            // Constructor for a candidate method that has no parameters.
            internal CandidateMember(MemberInfo member)
                : this(member, noParameters, noSignature, Form.Normal)
            { 
            }
 
            internal bool IsExpanded 
            {
                get { return form == Form.Expanded; } 
            }

            [SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
            internal int CompareMember(Type targetType, CandidateMember other, List arguments, RuleValidation validator) 
            {
                int better = 1; 
                int worse = -1; 
                int equal = 0;
 
                // Methods in a base class are not candidates if any method in a derived class
                // is applicable.
                Type thisDeclaringType = this.Member.DeclaringType;
                Type otherDeclaringType = other.Member.DeclaringType; 
                if (thisDeclaringType != otherDeclaringType)
                { 
                    if (TypeProvider.IsAssignable(otherDeclaringType, thisDeclaringType)) 
                    {
                        // This declaring type can be converted to the other declaring type, 
                        // which means this one is more derived.
                        return better;
                    }
                    else if (TypeProvider.IsAssignable(thisDeclaringType, otherDeclaringType)) 
                    {
                        // The other declaring type can be converted to this declaring type, 
                        // which means the other one is more derived. 
                        return worse;
                    } 
                }

                System.Diagnostics.Debug.Assert(arguments.Count == this.signature.Count);
                System.Diagnostics.Debug.Assert(arguments.Count == other.signature.Count); 

                bool hasAtLeastOneBetterConversion = false; 
                bool hasAtLeastOneWorseConversion = false; 
                bool signaturesAreIdentical = true;
 
                // pick non-extension methods over extension methods
                // if both are extension methods, then pick the one in the namespace closest to "this"
                ExtensionMethodInfo thisExtension = this.Member as ExtensionMethodInfo;
                ExtensionMethodInfo otherExtension = other.Member as ExtensionMethodInfo; 
                if ((thisExtension == null) && (otherExtension != null))
                    return better; 
                else if ((thisExtension != null) && (otherExtension == null)) 
                    return worse;
                else if ((thisExtension != null) && (otherExtension != null)) 
                {
                    // we have 2 extension methods, which one is better
                    string[] thisNameSpace = thisExtension.DeclaringType.FullName.Split('.');
                    string[] otherNameSpace = otherExtension.DeclaringType.FullName.Split('.'); 
                    string[] bestNameSpace = validator.thisType.FullName.Split('.');
                    int thisMatch = MatchNameSpace(thisNameSpace, bestNameSpace); 
                    int otherMatch = MatchNameSpace(otherNameSpace, bestNameSpace); 
                    if (thisMatch > otherMatch)
                        return better; 
                    else if (thisMatch < otherMatch)
                        return worse;

                    // compare arguments, including the "this" argument 
                    CandidateParameter thisDeclaringParam = new CandidateParameter(thisExtension.AssumedDeclaringType);
                    CandidateParameter otherDeclaringParam = new CandidateParameter(otherExtension.AssumedDeclaringType); 
                    if (!thisDeclaringParam.Equals(otherDeclaringParam)) 
                    {
                        signaturesAreIdentical = false; 
                        int conversionResult = thisDeclaringParam.CompareConversion(otherDeclaringParam, new Argument(targetType));
                        if (conversionResult < 0)
                        {
                            // A conversion was found that was worse, so this candidate is not better. 
                            hasAtLeastOneWorseConversion = true;
                        } 
                        else if (conversionResult > 0) 
                        {
                            // This candidate had at least one conversion that was better.  (But 
                            // we have to keep looking in case there's one that's worse.)
                            hasAtLeastOneBetterConversion = true;
                        }
                    } 

                    // this check compares parameter lists correctly (see below) 
                    for (int p = 0; p < arguments.Count; ++p) 
                    {
                        CandidateParameter thisParam = this.signature[p]; 
                        CandidateParameter otherParam = other.signature[p];

                        if (!thisParam.Equals(otherParam))
                            signaturesAreIdentical = false; 

                        int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); 
                        if (conversionResult < 0) 
                        {
                            // A conversion was found that was worse, so this candidate is not better. 
                            hasAtLeastOneWorseConversion = true;
                        }
                        else if (conversionResult > 0)
                        { 
                            // This candidate had at least one conversion that was better.  (But
                            // we have to keep looking in case there's one that's worse.) 
                            hasAtLeastOneBetterConversion = true; 
                        }
                    } 
                    if (hasAtLeastOneBetterConversion && !hasAtLeastOneWorseConversion)
                    {
                        // At least one conversion was better than the "other" candidate
                        // and no other arguments were worse, so this one is better. 
                        return better;
                    } 
                    else if (!hasAtLeastOneBetterConversion && hasAtLeastOneWorseConversion) 
                    {
                        // At least one conversion was worse than the "other" candidate 
                        // and no other arguments were better, so this one is worse.
                        return worse;
                    }
                } 
                else
                { 
                    // NOTE: this is the original v1 code 
                    // It doesn't check for worse parameters correctly.
                    // However, for backwards compatability, we can't change it 
                    for (int p = 0; p < arguments.Count; ++p)
                    {
                        CandidateParameter thisParam = this.signature[p];
                        CandidateParameter otherParam = other.signature[p]; 

                        if (!thisParam.Equals(otherParam)) 
                            signaturesAreIdentical = false; 

                        int conversionResult = thisParam.CompareConversion(otherParam, arguments[p]); 
                        if (conversionResult < 0)
                        {
                            // A conversion was found that was worse, so this candidate is not better.
                            return worse; 
                        }
                        else if (conversionResult > 0) 
                        { 
                            // This candidate had at least one conversion that was better.  (But
                            // we have to keep looking in case there's one that's worse.) 
                            hasAtLeastOneBetterConversion = true;
                        }
                    }
 
                    if (hasAtLeastOneBetterConversion)
                    { 
                        // At least one conversion was better than the "other" candidate, so this one 
                        // is better.
                        return better; 
                    }
                }

                if (signaturesAreIdentical) 
                {
                    // The signatures were "tied".  Try some disambiguating rules for expanded signatures 
                    // vs normal signatures. 
                    if (this.form == Form.Normal && other.form == Form.Expanded)
                    { 
                        // This candidate matched in its normal form, but the other one matched only after
                        // expansion of a params array.  This one is better.
                        return better;
                    } 
                    else if (this.form == Form.Expanded && other.form == Form.Normal)
                    { 
                        // This candidate matched in its expanded form, but the other one matched in its 
                        // normal form.  The other one was better.
                        return worse; 
                    }
                    else if (this.form == Form.Expanded && other.form == Form.Expanded)
                    {
                        // Both candidates matched in their expanded forms. 

                        int thisParameterCount = this.memberParameters.Length; 
                        int otherParameterCount = other.memberParameters.Length; 

                        if (thisParameterCount > otherParameterCount) 
                        {
                            // This candidate had more declared parameters, so it is better.
                            return better;
                        } 
                        else if (otherParameterCount > thisParameterCount)
                        { 
                            // The other candidate had more declared parameters, so it was better. 
                            return worse;
                        } 
                    }
                }

                // Nothing worked, the two candidates are equally applicable. 
                return equal;
            } 
 
            private static int MatchNameSpace(string[] test, string[] reference)
            { 
                // returns the number of strings in test that are the same as reference
                int i;
                int len = Math.Min(test.Length, reference.Length);
                for (i = 0; i < len; ++i) 
                {
                    if (test[i] != reference[i]) 
                        break; 
                }
                return i; 
            }
        }

        // Get the candidate target types, ordered from most-derived to least-derived. 
        private static List GetCandidateTargetTypes(Type targetType)
        { 
            List candidateTypes; 

            if (targetType.IsInterface) 
            {
                candidateTypes = new List();
                candidateTypes.Add(targetType);
 
                // Add all base interfaces in its hierarchy to the candidate list.
                for (int i = 0; i < candidateTypes.Count; ++i) 
                { 
                    Type currentCandidate = candidateTypes[i];
                    candidateTypes.AddRange(currentCandidate.GetInterfaces()); 
                }

                // Finally, add "System.Object", since all types intrinsically derive from this.
                candidateTypes.Add(typeof(object)); 
            }
            else 
            { 
                // It was a class; just add the one class.
                candidateTypes = new List(1); 
                candidateTypes.Add(targetType);
            }

            return candidateTypes; 
        }
 
        private delegate ValidationError BuildArgCountMismatchError(string name, int numArguments); 

        private static void EvaluateCandidate(List candidates, MemberInfo candidateMember, ParameterInfo[] parameters, List arguments, out ValidationError error, BuildArgCountMismatchError buildArgCountMismatchError) 
        {
            error = null;

            int numArguments = arguments.Count; 
            string candidateName = candidateMember.Name;
 
            if (parameters == null || parameters.Length == 0) 
            {
                // If there were no arguments supplied, and this method has no parameters, 
                // then it's a candidate.  (It should be the only one.)
                if (numArguments == 0)
                {
                    candidates.Add(new CandidateMember(candidateMember)); 
                }
                else 
                { 
                    error = buildArgCountMismatchError(candidateName, numArguments);
                } 
            }
            else
            {
                List signature = new List(); 

                int parameterCount = parameters.Length; 
 
                int fixedParameterCount = parameterCount;
 
                // Check to see if the last parameter is (1) an array and (2) has a ParamArrayAttribute
                // (i.e., it is a "params" array).
                ParameterInfo lastParam = parameters[parameterCount - 1];
                if (lastParam.ParameterType.IsArray) 
                {
                    object[] attrs = lastParam.GetCustomAttributes(typeof(ParamArrayAttribute), false); 
                    if (attrs != null && attrs.Length > 0) 
                        fixedParameterCount -= 1;
                } 

                if (numArguments < fixedParameterCount)
                {
                    // Not enough arguments were passed for this to be a candidate. 
                    error = buildArgCountMismatchError(candidateName, numArguments);
 
                    return; 
                }
                else if (fixedParameterCount == parameterCount && numArguments != parameterCount) 
                {
                    // Too many arguments were passed for this to be a candidate.
                    error = buildArgCountMismatchError(candidateName, numArguments);
 
                    return;
                } 
 
                // For the fixed part of the method signature, make sure each argument can
                // be implicitly converted to the corresponding parameter. 
                int p = 0;
                for (; p < fixedParameterCount; ++p)
                {
                    CandidateParameter candidateParam = new CandidateParameter(parameters[p]); 
                    if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error))
                        break; // argument #p didn't match 
 
                    // If we get here, then so far so good.
                    signature.Add(candidateParam); 
                }

                if (p != fixedParameterCount)
                { 
                    // We didn't match all of the fixed part.  This method is not a candidate.
                    return; 
                } 

                if (fixedParameterCount < parameterCount) 
                {
                    // The last parameter was a "params" array.  As long as zero or more arguments
                    // are assignable, it's a valid candidate in the expanded form.
 
                    CandidateMember candidateMethod = null;
 
                    if (numArguments == fixedParameterCount) 
                    {
                        // Zero arguments were passed as the params array.  The method is a candidate 
                        // in its expanded form.
                        candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
                    }
                    else if (numArguments == parameterCount) 
                    {
                        // Special case:  one argument was passed as the params array. 
                        CandidateParameter candidateParam = new CandidateParameter(lastParam); 
                        if (candidateParam.Match(arguments[p], candidateName, p + 1, out error))
                        { 
                            // It was the same array type as the params array, so the candidate
                            // matched in its normal form.
                            signature.Add(candidateParam);
                            candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal); 
                        }
                    } 
 
                    if (candidateMethod == null)
                    { 
                        // One or more arguments were passed as the params array.  As long
                        // as they match the element type, this method is a candidate.
                        CandidateParameter candidateParam = new CandidateParameter(lastParam.ParameterType.GetElementType());
 
                        for (; p < numArguments; ++p)
                        { 
                            if (!candidateParam.Match(arguments[p], candidateName, p + 1, out error)) 
                            {
                                // Not all of the trailing arguments matched the params array's element type; 
                                // this cannot be a candidate.
                                return;
                            }
 
                            // If we get here, then so far so good.
                            signature.Add(candidateParam); 
                        } 

                        // All the trailing arguments matched, so this is a candidate in the expanded form. 
                        candidateMethod = new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Expanded);
                    }

                    candidates.Add(candidateMethod); 
                }
                else 
                { 
                    // The last parameter wasn't "params".  This candidate matched in its normal form.
                    candidates.Add(new CandidateMember(candidateMember, parameters, signature, CandidateMember.Form.Normal)); 
                }
            }
        }
 
        private CandidateMember FindBestCandidate(Type targetType, List candidates, List arguments)
        { 
            int numCandidates = candidates.Count; 
            Debug.Assert(numCandidates > 0, "expected at least one candidate");
 
            // Start by assuming the first candidate is the best one.
            List bestCandidates = new List(1);
            bestCandidates.Add(candidates[0]);
 
            // Go through the rest of the candidates and try to find a better one.  (If
            // there are no more candidates, then there was only one, and that's the right 
            // one.) 
            for (int i = 1; i < numCandidates; ++i)
            { 
                CandidateMember newCandidate = candidates[i];

                // Compare this new candidate one if the current "best" ones.  (If there
                // is currently more than one best candidate, then so far its ambiguous, which 
                // means all the best ones are equally good.  Thus if this new candidate
                // is better than one, it's better than all. 
                CandidateMember bestCandidate = bestCandidates[0]; 

                int comparison = newCandidate.CompareMember(targetType, bestCandidate, arguments, this); 
                if (comparison > 0)
                {
                    // The new one was better than at least one of the best ones.  It
                    // becomes the new best one. 
                    bestCandidates.Clear();
                    bestCandidates.Add(newCandidate); 
                } 
                else if (comparison == 0)
                { 
                    // The new one was no better, so add it to the list of current best.
                    // (Unless we find a better one, it's ambiguous so far.)
                    bestCandidates.Add(newCandidate);
                } 
            }
 
            if (bestCandidates.Count == 1) 
            {
                // Good, there was exactly one best match. 
                return bestCandidates[0];
            }

            // Otherwise, it must have been ambiguous. 
            return null;
        } 
 
        internal MethodInfo FindBestCandidate(Type targetType, List methods, params Type[] types)
        { 
            List arguments = new List();
            foreach (Type t in types)
                arguments.Add(new Argument(t));
 
            List candidates = new List(methods.Count);
            foreach (MethodInfo method in methods) 
            { 
                ValidationError tempError = null;
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError, 
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments);
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch); 
                                  });
            } 
            if (candidates.Count == 0) 
            {
                // nothing looks useful 
                return null;
            }
            CandidateMember result = FindBestCandidate(targetType, candidates, arguments);
            return (result != null) ? (MethodInfo)result.Member : null; 
        }
 
        internal RuleConstructorExpressionInfo ResolveConstructor(Type targetType, BindingFlags constructorBindingFlags, List argumentExprs, out ValidationError error) 
        {
            string message; 

            List arguments = new List(argumentExprs.Count);
            foreach (CodeExpression argumentExpr in argumentExprs)
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all candidate methods contained in them. 
            List candidateTypes = GetCandidateTargetTypes(targetType); 
            // Get all methods by this name...
            List constructors = GetConstructors(candidateTypes, constructorBindingFlags); 
            if (constructors.Count == 0)
            {
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownConstructor, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists); 
                return null;
            } 
 
            // Cull the list of methods to those which match the supplied arguments.
            List candidateConstructors = GetCandidateConstructors(constructors, arguments, out error); 

            // If the list is null, then no candidates matched.
            if (candidateConstructors == null)
                return null; 

            // We found candidate methods in this type. 
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateConstructors, arguments); 

            if (bestCandidate == null) 
            {
                // It was ambiguous.
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousConstructor, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 
                return null;
            } 
 
            // We found the best match.
            return new RuleConstructorExpressionInfo((ConstructorInfo)bestCandidate.Member, bestCandidate.IsExpanded); 
        }

        internal RuleMethodInvokeExpressionInfo ResolveMethod(Type targetType, string methodName, BindingFlags methodBindingFlags, List argumentExprs, out ValidationError error)
        { 
            string message;
 
            List arguments = new List(argumentExprs.Count); 
            foreach (CodeExpression argumentExpr in argumentExprs)
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all candidate methods contained in them.
            List candidateTypes = GetCandidateTargetTypes(targetType);
            // Get all methods by this name... 
            List methods = GetNamedMethods(candidateTypes, methodName, methodBindingFlags);
            if (methods.Count == 0) 
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownMethod, methodName, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_MethodNotExists); 
                return null;
            }

            // Cull the list of methods to those which match the supplied arguments. 
            List candidateMethods = GetCandidateMethods(methodName, methods, arguments, out error);
 
            // If the list is null, then no candidates matched. 
            if (candidateMethods == null)
                return null; 

            // We found candidate methods in this type.
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateMethods, arguments);
 
            if (bestCandidate == null)
            { 
                // It was ambiguous. 
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousMatch, methodName);
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember); 

                return null;
            }
 
            // We found the best match.
            MethodInfo theMethod = (MethodInfo)bestCandidate.Member; 
            if (theMethod != null) 
            {
                IsAuthorized(theMethod.ReturnType); 
            }
            return new RuleMethodInvokeExpressionInfo(theMethod, bestCandidate.IsExpanded);
        }
 
        internal static List GetConstructors(List targetTypes, BindingFlags constructorBindingFlags)
        { 
            List methods = new List(); 

            for (int t = 0; t < targetTypes.Count; ++t) 
            {
                Type targetType = targetTypes[t];

                // Go through all the constructors on the target type 
                ConstructorInfo[] members = targetType.GetConstructors(constructorBindingFlags);
                for (int m = 0; m < members.Length; ++m) 
                { 
                    ConstructorInfo constructor = members[m];
                    if (constructor.IsGenericMethod) // skip generic constructors 
                        continue;
                    if (constructor.IsStatic) // skip static constructors
                        continue;
                    if (constructor.IsPrivate) // skip private constructors 
                        continue;
                    if (constructor.IsFamily) // skip internal constructors 
                        continue; 
                    methods.Add(constructor);
                } 
            }
            return methods;
        }
 
        private List GetNamedMethods(List targetTypes, string methodName, BindingFlags methodBindingFlags)
        { 
            List methods = new List(); 
            List currentExtensionMethods = ExtensionMethods;
            for (int t = 0; t < targetTypes.Count; ++t) 
            {
                Type targetType = targetTypes[t];

                // Go through all the methods on the target type that have matching names. 
                MemberInfo[] members = targetType.GetMember(methodName, MemberTypes.Method, methodBindingFlags);
                for (int m = 0; m < members.Length; ++m) 
                { 
                    MethodInfo method = (MethodInfo)members[m];
                    if (!method.IsGenericMethod) // skip generic methods 
                        methods.Add(method);
                }

                // add in any extension methods that match 
                foreach (ExtensionMethodInfo extension in currentExtensionMethods)
                { 
                    // does it have the right name and is the type compatible 
                    ValidationError error;
                    if ((extension.Name == methodName) && 
                        TypesAreAssignable(targetType, extension.AssumedDeclaringType, null, out error))
                    {
                        // possible match
                        methods.Add(extension); 
                    }
                } 
            } 

            return methods; 
        }

        private List extensionMethods;
        private List seenAssemblies; 
        private const string ExtensionAttributeFullName = "System.Runtime.CompilerServices.ExtensionAttribute, " + AssemblyRef.SystemCore;
        private Type extensionAttribute; 
 
        private static Type defaultExtensionAttribute = GetDefaultExtensionAttribute();
 
        private static Type GetDefaultExtensionAttribute()
        {
            return Type.GetType(ExtensionAttributeFullName, false);
        } 

        // The extensionAttributeType may still be null after calling this method 
        // if, for example, we are in a 3.0 SP2 environment. 
        private void SetExtensionAttribute()
        { 
            // use the TypeProvider first
            extensionAttribute = typeProvider.GetType(ExtensionAttributeFullName, false);
            if (extensionAttribute == null)
            { 
                extensionAttribute = defaultExtensionAttribute;
            } 
        } 

        internal List ExtensionMethods 
        {
            get
            {
                if (extensionMethods == null) 
                    DetermineExtensionMethods();
 
                return extensionMethods; 
            }
        } 

        private void DetermineExtensionMethods()
        {
            extensionMethods = new List(); 

            SetExtensionAttribute(); 
            if (extensionAttribute != null) 
            {
                seenAssemblies = new List(); 
                Assembly localAssembly = typeProvider.LocalAssembly;
                if (localAssembly != null)
                {
                    DetermineExtensionMethods(localAssembly); 
                    foreach (Assembly a in typeProvider.ReferencedAssemblies)
                        DetermineExtensionMethods(a); 
                } 
                else
                { 
                    // probably at design-time, nothing compiled yet
                    // go through all types it knows about
                    DetermineExtensionMethods(typeProvider.GetTypes());
                } 
            }
        } 
 
        internal void DetermineExtensionMethods(Assembly assembly)
        { 
            // when this method is called outside of this class, we must have tried
            // getting ExtensionMethods. So we must have tried setting extensionAttributeType.

            if (extensionAttribute != null) 
            {
                if ((assembly != null) && (!seenAssemblies.Contains(assembly))) 
                { 
                    seenAssemblies.Add(assembly);
                    if (IsMarkedExtension(assembly)) 
                    {
                        Type[] types;
                        try
                        { 
                            types = assembly.GetTypes();
                        } 
                        catch (ReflectionTypeLoadException e) 
                        {
                            // problems loading all the types, take what we can get 
                            // some types will be null
                            types = e.Types;
                        }
                        DetermineExtensionMethods(types); 
                    }
                } 
            } 
        }
 
        private void DetermineExtensionMethods(Type[] types)
        {
            foreach (Type type in types)
            { 
                // static classes are defined as "abstract sealed"
                // Note: VB doesn't support static classes, so the modules are only defined as "sealed" 
                if ((type != null) && (type.IsPublic || type.IsNestedPublic) && (type.IsSealed) && (IsMarkedExtension(type))) 
                {
                    // looks like a class containing extension methods, let's find them 
                    MethodInfo[] staticMethods = type.GetMethods(BindingFlags.Static | BindingFlags.Public);
                    foreach (MethodInfo mi in staticMethods)
                    {
                        // skip generic methods 
                        if ((mi.IsStatic) && !(mi.IsGenericMethod) && (IsMarkedExtension(mi)))
                        { 
                            ParameterInfo[] parms = mi.GetParameters(); 
                            if (parms.Length > 0 && parms[0].ParameterType != null)
                            { 
                                extensionMethods.Add(new ExtensionMethodInfo(mi, parms));
                            }
                        }
                    } 
                }
            } 
        } 

        private bool IsMarkedExtension(Assembly assembly) 
        {
            if (extensionAttribute != null)
            {
                object[] objAttrs = assembly.GetCustomAttributes(extensionAttribute, false); 
                if (objAttrs != null && objAttrs.Length > 0)
                    return true; 
            } 

            return false; 
        }

        private bool IsMarkedExtension(Type type)
        { 
            if (extensionAttribute != null)
            { 
                object[] objAttrs = type.GetCustomAttributes(extensionAttribute, false); 
                if (objAttrs != null && objAttrs.Length > 0)
                    return true; 
            }

            return false;
        } 

        private bool IsMarkedExtension(MethodInfo mi) 
        { 
            if (extensionAttribute != null)
            { 
                object[] objAttrs = mi.GetCustomAttributes(extensionAttribute, false);
                if (objAttrs != null && objAttrs.Length > 0)
                    return true;
            } 

            return false; 
        } 

        static List GetCandidateMethods(string methodName, List methods, List arguments, out ValidationError error) 
        {
            List candidates = new List();

            error = null; 

            int errorCount = 0; 
            foreach (MethodInfo method in methods) 
            {
                ValidationError tempError = null; 
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments); 
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
                                  }); 
 
                error = tempError;
                if (tempError != null) 
                    ++errorCount;
            }

            if (candidates.Count == 0) 
            {
                // No candidates were found. 
 
                if (errorCount > 1)
                { 
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodOverloadNotFound, methodName);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound); 
                }
 
                return null; 
            }
            else 
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null;
            } 

            return candidates; 
        } 

        static List GetCandidateConstructors(List constructors, List arguments, out ValidationError error) 
        {
            List candidates = new List();

            error = null; 

            int errorCount = 0; 
            foreach (ConstructorInfo method in constructors) 
            {
                ValidationError tempError = null; 
                EvaluateCandidate(candidates, method, method.GetParameters(), arguments, out tempError,
                                  delegate(string name, int numArguments)
                                  {
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.MethodArgCountMismatch, name, numArguments); 
                                      return new ValidationError(message, ErrorNumbers.Error_MethodArgCountMismatch);
                                  }); 
 
                error = tempError;
                if (tempError != null) 
                    ++errorCount;
            }

            if (candidates.Count == 0) 
            {
                // No candidates were found. 
 
                if (errorCount > 1)
                { 
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.ConstructorOverloadNotFound);
                    error = new ValidationError(message, ErrorNumbers.Error_MethodOverloadNotFound); 
                }
 
                return null; 
            }
            else 
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null;
            } 

            return candidates; 
        } 

        internal RulePropertyExpressionInfo ResolveIndexerProperty(Type targetType, BindingFlags bindingFlags, List argumentExprs, out ValidationError error) 
        {
            string message;

            int numArgs = argumentExprs.Count; 

            if (numArgs < 1) 
            { 
                // Must have at least one indexer!
                message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArgs); 
                error = new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch);
                return null;
            }
 
            List arguments = new List(numArgs);
            foreach (CodeExpression argumentExpr in argumentExprs) 
                arguments.Add(new Argument(argumentExpr, this)); 

            // Get the candidate types and all the candidate indexer properties contained in them. 
            List candidateTypes = GetCandidateTargetTypes(targetType);
            List indexerProperties = GetIndexerProperties(candidateTypes, bindingFlags);
            if (indexerProperties.Count == 0)
            { 
                message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerNotFound, RuleDecompiler.DecompileType(targetType));
                error = new ValidationError(message, ErrorNumbers.Error_IndexerNotFound); 
                return null; 
            }
 
            List candidateIndexers = GetCandidateIndexers(indexerProperties, arguments, out error);

            // If the list is null, then no candidates matched.
            if (candidateIndexers == null) 
                return null;
 
            // We found candidate methods in this type. 
            CandidateMember bestCandidate = FindBestCandidate(targetType, candidateIndexers, arguments);
 
            if (bestCandidate == null)
            {
                // It was ambiguous.
                message = string.Format(CultureInfo.CurrentCulture, Messages.AmbiguousIndexerMatch); 
                error = new ValidationError(message, ErrorNumbers.Error_CannotResolveMember);
 
                return null; 
            }
 
            // We found the best match.
            PropertyInfo pi = (PropertyInfo)bestCandidate.Member;
            if (pi != null)
            { 
                IsAuthorized(pi.PropertyType);
            } 
            return new RulePropertyExpressionInfo(pi, pi.PropertyType, bestCandidate.IsExpanded); 
        }
 
        private static List GetIndexerProperties(List candidateTypes, BindingFlags bindingFlags)
        {
            List indexerProperties = new List();
 
            foreach (Type targetType in candidateTypes)
            { 
                object[] attrs = targetType.GetCustomAttributes(typeof(DefaultMemberAttribute), true); 
                if (attrs == null || attrs.Length == 0)
                    continue; 

                DefaultMemberAttribute[] defaultMemberAttrs = (DefaultMemberAttribute[])attrs;

                PropertyInfo[] properties = targetType.GetProperties(bindingFlags); 
                for (int p = 0; p < properties.Length; ++p)
                { 
                    PropertyInfo pi = properties[p]; 

                    // Select only those properties whose name matches the default name. 
                    bool matchedName = false;
                    for (int dm = 0; dm < defaultMemberAttrs.Length; ++dm)
                    {
                        if (defaultMemberAttrs[dm].MemberName == pi.Name) 
                        {
                            matchedName = true; 
                            break; 
                        }
                    } 

                    if (matchedName)
                    {
                        // We matched the name... 
                        ParameterInfo[] indexerParameters = pi.GetIndexParameters();
                        if (indexerParameters.Length > 0) 
                        { 
                            // ... and have indexer parameters; therefore, this is
                            // an interesting property. 
                            indexerProperties.Add(pi);
                        }
                    }
                } 
            }
 
            return indexerProperties; 
        }
 
        private static List GetCandidateIndexers(List indexerProperties, List arguments, out ValidationError error)
        {
            List candidates = new List();
 
            error = null;
 
            int errorCount = 0; 
            foreach (PropertyInfo indexerProp in indexerProperties)
            { 
                ValidationError tempError = null;
                EvaluateCandidate(candidates, indexerProp, indexerProp.GetIndexParameters(), arguments, out tempError,
                                  delegate(string propName, int numArguments)
                                  { 
                                      string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerCountMismatch, numArguments);
                                      return new ValidationError(message, ErrorNumbers.Error_IndexerCountMismatch); 
                                  }); 

                error = tempError; 
                if (tempError != null)
                    ++errorCount;
            }
 
            if (candidates.Count == 0)
            { 
                // No candidates were found. 

                if (errorCount > 1) 
                {
                    // If multiple candidates generated errors, then use a more generic error that says
                    // we couldn't find a matching overload.
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.IndexerOverloadNotFound); 
                    error = new ValidationError(message, ErrorNumbers.Error_IndexerOverloadNotFound);
                } 
 
                return null;
            } 
            else
            {
                // If there are any candidates, then wipe out any errors left over from any mismatches.
                error = null; 
            }
 
            return candidates; 
        }
 
        #endregion

        #region Type resolution
 
        internal void AddTypeReference(CodeTypeReference typeRef, Type type)
        { 
            typeRefMap[typeRef] = type; 
        }
 
        internal Type ResolveType(CodeTypeReference typeRef)
        {
            Type resultType = null;
 
            if (!typeRefMap.TryGetValue(typeRef, out resultType))
            { 
                string message; 

                resultType = FindType(typeRef.BaseType); 

                if (resultType == null)
                {
                    // check if we have a qualifiedname saved, and if we do, use it 
                    string qualifiedName = typeRef.UserData[RuleUserDataKeys.QualifiedName] as string;
                    resultType = ResolveType(qualifiedName); 
                    if (resultType != null) 
                    {
                        // qualified name returned the complete type, save it and we're done 
                        typeRefMap.Add(typeRef, resultType);
                        return resultType;
                    }
                    message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownType, typeRef.BaseType); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType);
                    error.UserData[RuleUserDataKeys.ErrorObject] = typeRef; 
                    Errors.Add(error); 
                    return null;
                } 

                // Handle generic type arguments.
                if (typeRef.TypeArguments.Count > 0)
                { 
                    Type[] typeArguments = new Type[typeRef.TypeArguments.Count];
                    for (int i = 0; i < typeRef.TypeArguments.Count; ++i) 
                    { 
                        // design-time types don't have fully-qualified names, so when they are
                        // used in a generic CodeTypeReference constructor leaves them with [] 
                        // surrounding them. Remove the [] if possible
                        CodeTypeReference arg = typeRef.TypeArguments[i];
                        if (arg.BaseType.StartsWith("[", StringComparison.Ordinal))
                            arg.BaseType = arg.BaseType.Substring(1, arg.BaseType.Length - 2); 

                        typeArguments[i] = ResolveType(arg); 
                        if (typeArguments[i] == null) 
                            return null;
                    } 

                    resultType = resultType.MakeGenericType(typeArguments);
                    if (resultType == null)
                    { 
                        StringBuilder sb = new StringBuilder(typeRef.BaseType);
                        string prefix = "<"; 
                        foreach (Type t in typeArguments) 
                        {
                            sb.Append(prefix); 
                            prefix = ",";
                            sb.Append(RuleDecompiler.DecompileType(t));
                        }
                        sb.Append(">"); 
                        message = string.Format(CultureInfo.CurrentCulture, Messages.UnknownGenericType, sb.ToString());
                        ValidationError error = new ValidationError(message, ErrorNumbers.Error_UnableToResolveType); 
                        error.UserData[RuleUserDataKeys.ErrorObject] = typeRef; 
                        Errors.Add(error);
                        return null; 
                    }
                }

 
                if (resultType != null)
                { 
                    CodeTypeReference arrayTypeRef = typeRef; 
                    if (arrayTypeRef.ArrayRank > 0)
                    { 
                        do
                        {
                            resultType = (arrayTypeRef.ArrayRank == 1) ? resultType.MakeArrayType() : resultType.MakeArrayType(arrayTypeRef.ArrayRank);
 
                            arrayTypeRef = arrayTypeRef.ArrayElementType;
                        } while (arrayTypeRef.ArrayRank > 0); 
                    } 
                }
 
                if (resultType != null)
                {
                    typeRefMap.Add(typeRef, resultType);
 
                    // at runtime we may not have the assembly loaded, so keep the fully qualified name around
                    typeRef.UserData[RuleUserDataKeys.QualifiedName] = resultType.AssemblyQualifiedName; 
                } 
            }
 
            return resultType;
        }

        internal Type ResolveType(string qualifiedName) 
        {
            Type resultType = null; 
            if (qualifiedName != null) 
            {
                resultType = typeProvider.GetType(qualifiedName, false); 

                // if the Typeprovider can't find it, use the framework,
                // since it should be an AssemblyQualifiedName
                if (resultType == null) 
                    resultType = Type.GetType(qualifiedName, false);
 
            } 
            return resultType;
        } 

        private Type FindType(string typeName)
        {
            if (typeName == null) 
                throw new ArgumentNullException("typeName");
 
            Type type = null; 

            // do we know about this type 
            if (!typesUsed.TryGetValue(typeName, out type))
            {
                type = typeProvider.GetType(typeName, false);
 
                if (type != null)
                { 
                    typesUsed.Add(typeName, type); 

                    IsAuthorized(type); 
                }
            }

            return type; 
        }
 
        internal void IsAuthorized(Type type) 
        {
            Debug.Assert(!type.IsPointer && !type.IsByRef, 
            "IsAuthorized should not be called for a type that is a pointer or passed by reference : " + type.AssemblyQualifiedName);
            if (checkStaticType)
            {
                if (authorizedTypes == null) 
                {
                    ValidationError error = new ValidationError(Messages.Error_ConfigFileMissingOrInvalid, ErrorNumbers.Error_ConfigFileMissingOrInvalid); 
                    Errors.Add(error); 
                }
                else 
                {
                    while (type.IsArray)
                    {
                        type = type.GetElementType(); 
                    }
                    if (type.IsGenericType) 
                    { 
                        IsAuthorizedSimpleType(type.GetGenericTypeDefinition());
                        Type[] typeArguments = type.GetGenericArguments(); 
                        foreach (Type t in typeArguments)
                        {
                            IsAuthorized(t);
                        } 
                    }
                    else 
                    { 
                        IsAuthorizedSimpleType(type);
                    } 
                }
            }
        }
 
        void IsAuthorizedSimpleType(Type type)
        { 
            Debug.Assert((!type.IsGenericType || type.IsGenericTypeDefinition) && !type.HasElementType, 
                "IsAuthorizedSimpleType should not be called for a partially specialized generic type or a type that encompasses or refers to another type : " +
                type.AssemblyQualifiedName); 

            string qualifiedName = type.AssemblyQualifiedName;

            if (!typesUsedAuthorized.ContainsKey(qualifiedName)) 
            {
                bool authorized = false; 
                foreach (AuthorizedType authorizedType in authorizedTypes) 
                {
                    if (authorizedType.RegularExpression.IsMatch(qualifiedName)) 
                    {
                        authorized = (String.Compare(bool.TrueString, authorizedType.Authorized, StringComparison.OrdinalIgnoreCase) == 0);
                        if (!authorized)
                            break; 
                    }
                } 
                if (!authorized) 
                {
                    string message = string.Format(CultureInfo.CurrentCulture, Messages.Error_TypeNotAuthorized, type.FullName); 
                    ValidationError error = new ValidationError(message, ErrorNumbers.Error_TypeNotAuthorized);
                    error.UserData[RuleUserDataKeys.ErrorObject] = type;
                    Errors.Add(error);
                } 
                else
                { 
                    typesUsedAuthorized.Add(qualifiedName, type); 
                }
            } 
        }

        #endregion
 
        #endregion
    } 
    #endregion RuleValidator 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

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