// 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."); }