呼叫类型.使用泛型方法的接口上的GetRuntimeMethod返回null

本文关键字:GetRuntimeMethod 返回 null 接口 呼叫 泛型方法 类型 | 更新日期: 2023-09-27 18:05:59

我在我的一个c#项目中使用反射:它是针对Windows 8.1和Windows Phone 8.1的便携式类库。

在那个项目中,我有一个名为IMyInterface的接口,它有一个带泛型参数TGenericObject的方法DoSomething。我还有一个名为MyClass的类。在某一点上,我需要通过反射查找指定接口中的DoSomething方法。所以,我使用的是Type类的GetRuntimeMethod方法和实际参数的类型,在我的例子中是MyClass。

请记住,我在这里提供的例子只是为了突出我所面临的问题。实际情况是接口IMyInterface和类MyClass在另一个项目中。

这里是交易:我期待GetRuntimeMethod返回DoSomething方法的MethodInfo,但它没有:返回null。

是否有一些容易的东西,我错过了从IMyInterface找到DoSomething方法,或者我必须让手更脏?

public interface IMyInterface
{
    void DoSomething<TGenericObject>(TGenericObject myGenericObject);
}
public class MyClass
{ }
class Program
{
    static void Main(string[] args)
    {
        MyClass myClassInst = new MyClass();
        MethodInfo methodInfo = typeof (IMyInterface).GetRuntimeMethod("DoSomething", new [] { myClassInst.GetType() });
    }
}

呼叫类型.使用泛型方法的接口上的GetRuntimeMethod返回null

我能够编写我自己的扩展方法,实际做我期望从GetRuntimeMethod方法。困扰我的是,我仍然不明白为什么。net提供的GetRuntimeMethod方法在我的示例中返回null。

这是暂时解决我的问题的不完整类。这是一个非常幼稚的方法,但它是一个起点。那门课有很多东西没讲,但至少,它是一个让我能继续讲下去的答案。

public static class TypeExtensions
{
    #region Public Methods
    /// <summary>
    /// Looks for the method in the type matching the name and arguments.
    /// </summary>
    /// <param name="type"></param>
    /// <param name="methodName">
    /// The name of the method to find.
    /// </param>
    /// <param name="args">
    /// The types of the method's arguments to match.
    /// </param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException">
    /// Thrown if:
    ///     - The name of the method is not specified.
    /// </exception>
    public static MethodInfo GetRuntimeMethod(this Type type, string methodName, Type[] args)
    {
        if (ReferenceEquals(type, null))
            throw new NullReferenceException("The type has not been specified.");
        if (string.IsNullOrEmpty(methodName))
            throw new ArgumentNullException("methodName", "The name of the method has not been specified.");

        var methods = type.GetRuntimeMethods().Where(methodInfo => string.Equals(methodInfo.Name, methodName, StringComparison.OrdinalIgnoreCase)).ToList();
        if (!methods.Any())
            return null;    //  No methods have the specified name.
        if (methods.Count == 1)
        {
            MethodInfo methodInfo = methods.Single();
            return IsSignatureMatch(methodInfo, args) ? methodInfo : null;
        }
        //  Oh noes, don't make me go there.
        throw new NotImplementedException("Resolving overloaded methods is not implemented as of now.");
    }
    #endregion
    #region Private Methods
    /// <summary>
    /// Finds out if the provided arguments matches the specified method's signature.
    /// </summary>
    /// <param name="methodInfo"></param>
    /// <param name="args"></param>
    /// <returns></returns>
    private static bool IsSignatureMatch(MethodBase methodInfo, Type[] args)
    {
        Debug.Assert(!ReferenceEquals(methodInfo, null), "The methodInfo has not been specified.");

        //  Gets the parameters of the method to analyze.
        ParameterInfo[] parameters = methodInfo.GetParameters();
        int currentArgId = 0;
        foreach (ParameterInfo parameterInfo in parameters)
        {
            if (!ReferenceEquals(args, null) && currentArgId < args.Length)
            {
                //  Find out if the types matchs.
                if (parameterInfo.ParameterType == args[currentArgId])
                {
                    currentArgId++;
                    continue; //  Yeah! Try the next one.
                }
                //  Is this a generic parameter?
                if (parameterInfo.ParameterType.IsGenericParameter)
                {
                    //  Gets the base type of the generic parameter.
                    Type baseType = parameterInfo.ParameterType.GetTypeInfo().BaseType;

                    //  TODO: This is not good v and works with the most simple situation.
                    //  Does the base type match?  
                    if (args[currentArgId].GetTypeInfo().BaseType == baseType)
                    {
                        currentArgId++;
                        continue; //  Yeah! Go on to the next parameter.
                    }
                }
            }
            //  Is this parameter optional or does it have a default value?
            if (parameterInfo.IsOptional || parameterInfo.HasDefaultValue)
                continue; // Uhum. So let's ignore this parameter for now.
            //  No need to go further. It does not match :(
            return false;
        }
        //  Ye!
        return true;
    }
    #endregion
}
相关文章:
  • 没有找到相关文章