/// <summary> /// Finds the duck implementation for a given interface method. /// </summary> /// <param name="interfaceMethod">Interface method to find the implementation of.</param> /// <returns>If the type given in the constructor implements the given interface method, such method; otherwise, null.</returns> private MethodInfo FindDuckMethod(MethodInfo interfaceMethod) { MethodInfo duckMethod = null; int bestParameterCompatibilityScore = int.MinValue; MethodInfo[] methods = m_DuckType.GetMethods(); foreach (MethodInfo method in methods) { // If casting a static class, must be static; if not, must not be static if (method.IsStatic == m_IsDuckStatic) { // Must be public and have the same name if (method.IsPublic && method.Name == interfaceMethod.Name) { // Must both be non-generic or both generic if (method.IsGenericMethodDefinition == interfaceMethod.IsGenericMethodDefinition) { // Must have compatible generic arguments bool genericArgumentsMatch = false; if (method.IsGenericMethodDefinition) { Type[] genericArguments = method.GetGenericArguments(); Type[] interfaceGenericArguments = interfaceMethod.GetGenericArguments(); if (genericArguments.Length == interfaceGenericArguments.Length) { // TODO: Check generic argument constraints. genericArgumentsMatch = true; } } else { genericArgumentsMatch = true; } if (genericArgumentsMatch) { // Must have a compatible parameter list int parameterCompatibilityScore = 0; ParameterInfo[] parameters = method.GetParameters(); ParameterInfo[] interfaceMethodParameters = interfaceMethod.GetParameters(); if (parameters.Length == interfaceMethodParameters.Length) { bool areParameterTypesCompatible = true; for (int i = 0; i < parameters.Length; i++) { if (!DuckTyping.AreTypesCompatible(parameters[i].ParameterType, interfaceMethodParameters[i].ParameterType, true)) { areParameterTypesCompatible = false; break; } parameterCompatibilityScore += DuckTyping.GetTypeCompatibilityScore(parameters[i].ParameterType, interfaceMethodParameters[i].ParameterType); } if (areParameterTypesCompatible) { // Must have a compatible return type if (DuckTyping.AreTypesCompatible(interfaceMethod.ReturnType, method.ReturnType, true)) { parameterCompatibilityScore += DuckTyping.GetTypeCompatibilityScore(interfaceMethod.ReturnType, method.ReturnType); // Since there may be multiple method overloads that are compatible with the // interface method, we want to choose the best one. if (parameterCompatibilityScore > bestParameterCompatibilityScore) { duckMethod = method; bestParameterCompatibilityScore = parameterCompatibilityScore; } } } } } } } } } return(duckMethod); }