// This method returns true if the specified argument types match
    // the method's parameter types
    private static Boolean CompareParamAndArgTypes(
        ParameterInfo[] paramTypes,
        Type[] argTypes,
        CompareParamAndArgTypesFlags flags)
    {
        // This binder requires that the number of arguments and parameters match
        if (paramTypes.Length != argTypes.Length)
        {
            return(false);
        }

        Int32 i = 0;

        for (; i < paramTypes.Length; i++)
        {
            // If the argument has a type, compare it against the parameter's type
            // This can be null if Type.InvokeMember is passed null for an argument
            if (argTypes[i] != null)
            {
                Type formalType = paramTypes[i].ParameterType;

                // If argument and parameter types match exactly, try next pair
                if (formalType == argTypes[i])
                {
                    continue;
                }

                // Compare the primitive, value type, or enumerated type parameter
                if (formalType.IsValueType)
                {
                    if (((flags & CompareParamAndArgTypesFlags.CoerceValueTypes) != 0) &&
                        CanConvertPrimitiveType(argTypes[i], formalType))
                    {
                        continue;
                    }
                    break; // Can't coerce argument type to parameter type
                }
                else
                {
                    // Compare the reference type parameter
                    if (((flags & CompareParamAndArgTypesFlags.AllowBaseTypes) != 0) &&
                        formalType.IsAssignableFrom(argTypes[i]))
                    {
                        continue;
                    }
                    break; // Can't implicitly cast argument type to parameter type
                }
            }
        }

        // Return true if all argument and parameter types match
        return(i == paramTypes.Length);
    }
    // GetProperty calls this method to select a specific property.
    // This code performs uses simple conversion rules to bind.
    public override PropertyInfo SelectProperty(
        BindingFlags bindingAttr,      // Flags to restrict options
        PropertyInfo[] properties,     // Property subset selected by reflection
        Type returnType,               // Property's return type
        Type[] argTypes,               // Set of argument types
        ParameterModifier[] modifiers) // Modifiers (usually ignored)
    // This ArrayList contains the set of possible properties
    {
        ArrayList candidates = new ArrayList();

        // Build the set of candidate properties removing any property that
        // doesn't have the specified number of arguments.

        // Only consider properties that have the same number of arguments and type
        Int32 argCount = (argTypes == null) ? 0 : argTypes.Length;

        foreach (PropertyInfo p in properties)
        {
            if (GetPropertyParams(p).Length == argCount)
            {
                // Check the property's type
                if ((returnType == null) || (returnType == p.PropertyType))
                {
                    candidates.Add(p);
                }
            }
        }

        // If no exact match was found and the caller wants an exact match, throw
        Int32 numTests = ((BindingFlags.ExactBinding & bindingAttr) != 0) ? 1 : 3;

        for (Int32 test = 0; test < numTests; test++)
        {
            CompareParamAndArgTypesFlags flags = CompareParamAndArgTypesFlags.Exact;

            // Look for properties whose parameter types exactly match the argument types
            if (test == 0)
            {
                flags = CompareParamAndArgTypesFlags.Exact;
            }

            // Look for properties that can accomodate the parameters passed.
            if (test == 1)
            {
                flags = CompareParamAndArgTypesFlags.AllowBaseTypes;
            }

            // Check whether any conversion could be applied on primitives as well.
            // NOTE: We bind to the first matching property; not the best matching property.
            // Look for properties that can accomodate the parameters passed.
            if (test == 2)
            {
                flags = CompareParamAndArgTypesFlags.AllowBaseTypes |
                        CompareParamAndArgTypesFlags.CoerceValueTypes;
            }

            // Assume that no property matches the argument's parameters
            PropertyInfo match = null;

            // Check ALL of the properties
            foreach (PropertyInfo p in candidates)
            {
                if (CompareParamAndArgTypes(GetPropertyParams(p), argTypes, flags))
                {
                    // A matching property was found

                    // If we found a matching property previously, then we don't know
                    // how to select one of them.
                    if (match != null)
                    {
                        // Note, when doing an exact match this can occur if multiple
                        // properties differ only by type
                        throw new AmbiguousMatchException("Multiple properties match the specified parameter types.");
                    }

                    // Save the matching property
                    match = p;
                }
            }

            // One matching property was found, return it
            if (match != null)
            {
                return(match);
            }
        }

        // No matching property was found, throw
        throw new MissingMemberException("Member not found.");
    }
    // GetMethod calls this method to select a specific method.
    // This code performs uses simple conversion rules to bind.
    public override MethodBase SelectMethod(
        BindingFlags bindingAttr,      // Flags to restrict options
        MethodBase[] methods,          // Method subset selected by reflection
        Type[] argTypes,               // Set of argument types
        ParameterModifier[] modifiers) // Modifiers (usually ignored)
    // This ArrayList contains the set of possible methods
    {
        ArrayList candidates = new ArrayList();

        // Build the set of candidate methods removing any method that
        // doesn't have the specified number of arguments.

        // A more sophisticated binder would have code here to deal with methods
        // that accept a variable number of arguments (ParamArrayAttribute) and
        // with methods that accept optional arguments and named parameters.

        Int32 argCount = argTypes.Length;

        foreach (MethodBase m in methods)
        {
            if (m.GetParameters().Length == argCount)
            {
                candidates.Add(m);
            }
        }

        // If no exact match was found and the caller wants an exact match, throw
        Int32 numTests = ((BindingFlags.ExactBinding & bindingAttr) != 0) ? 1 : 3;

        for (Int32 test = 0; test < numTests; test++)
        {
            CompareParamAndArgTypesFlags flags = CompareParamAndArgTypesFlags.Exact;

            // Look for methods whose parameter types exactly match the argument types
            if (test == 0)
            {
                flags = CompareParamAndArgTypesFlags.Exact;
            }

            // Look for methods that can accomodate the parameters passed.
            if (test == 1)
            {
                flags = CompareParamAndArgTypesFlags.AllowBaseTypes;
            }

            // Check whether any conversion could be applied on primitives as well.
            // NOTE: We bind to the first matching method; not the best matching method.
            // Look for methods that can accomodate the parameters passed.
            if (test == 2)
            {
                flags = CompareParamAndArgTypesFlags.AllowBaseTypes |
                        CompareParamAndArgTypesFlags.CoerceValueTypes;
            }

            // Assume that no method matches the argument's parameters
            MethodBase match = null;

            // Check ALL of the methods
            foreach (MethodBase m in candidates)
            {
                if (CompareParamAndArgTypes(m.GetParameters(), argTypes, flags))
                {
                    // A matching method was found

                    // If we found a matching method previously, then we don't know
                    // how to select one of them.
                    if (match != null)
                    {
                        // Note, when doing an exact match this can occur if multiple
                        // methods differ only by return type
                        throw new AmbiguousMatchException("Multiple methods match the specified parameter types.");
                    }

                    // Save the matching method
                    match = m;
                }
            }

            // One matching method was found, return it
            if (match != null)
            {
                return(match);
            }
        }

        // No matching method was found, throw
        throw new MissingMethodException("Member not found.");
    }