Example #1
0
        /// <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);
        }