【问题标题】:How do I distinguish between generic and non generic signatures using GetMethod in .NET?如何在 .NET 中使用 GetMethod 区分泛型和非泛型签名?
【发布时间】:2012-07-19 17:56:54
【问题描述】:

假设存在如下所述的类 X,我如何获取非泛型方法的方法信息?下面的代码会抛出异常。

using System;

class Program {
    static void Main(string[] args) {
        var mi = Type.GetType("X").GetMethod("Y"); // Ambiguous match found.
        Console.WriteLine(mi.ToString());
    }
}

class X {
    public void Y() {
        Console.WriteLine("I want this one");
    }
    public void Y<T>() {
        Console.WriteLine("Not this one");
    }
}

【问题讨论】:

    标签: .net c#-4.0


    【解决方案1】:

    不要使用GetMethod,使用GetMethods,然后检查IsGenericMethod

    using System;
    using System.Linq;
    
    class Program
    {
        static void Main(string[] args)
        {
            var mi = Type.GetType("X").GetMethods().Where(method => method.Name == "Y"); 
            Console.WriteLine(mi.First().Name + " generic? " + mi.First().IsGenericMethod);
            Console.WriteLine(mi.Last().Name + " generic? " + mi.Last().IsGenericMethod);
        }
    }
    
    class X
    {
        public void Y()
        {
            Console.WriteLine("I want this one");
        }
        public void Y<T>()
        {
            Console.WriteLine("Not this one");
        }
    }
    

    作为奖励 - 一种扩展方法:

    public static class TypeExtensions
    {
        public static MethodInfo GetMethod(this Type type, string name, bool generic)
        {
            if (type == null)
            {
                throw new ArgumentNullException("type");
            }
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }
            return type.GetMethods()
                .FirstOrDefault(method => method.Name == name & method.IsGenericMethod == generic);
        }
    }
    

    那么就:

    static void Main(string[] args)
    {
        MethodInfo generic = Type.GetType("X").GetMethod("Y", true);
        MethodInfo nonGeneric = Type.GetType("X").GetMethod("Y", false);
    }
    

    【讨论】:

    • 我很惊讶这不是 .NET 默认的一部分。
    【解决方案2】:

    根据 Konrad Morawski 的回答,我创建了一个增强的扩展方法:

    public static MethodInfo GetMethod (this Type i_oContainingType,
                                             string i_sMethodName,
                                             BindingFlags i_enBindingFlags,
                                             Type[] i_aoArgumentType,
                                             bool i_bGeneric)
    {
      if (i_oContainingType == null)
        throw new ArgumentNullException (nameof (i_oContainingType));
    
      var aoMethod = i_oContainingType.GetMethods (i_enBindingFlags);
      var listoMethod = new List<MethodInfo> ();
      foreach (var oMethod in aoMethod)
      {
        if (!string.Equals (oMethod.Name, i_sMethodName))
          continue;
        if (oMethod.IsGenericMethod != i_bGeneric)
          continue;
        var aoParameter = oMethod.GetParameters ();
        if (aoParameter.Length != i_aoArgumentType?.Length)
          continue;
        int iParamMatch = 0;
        for (int ixParam = 0; ixParam < aoParameter.Length; ixParam++)
        {
          if (aoParameter[ixParam].ParameterType == i_aoArgumentType[ixParam])
            iParamMatch++;
        }
        if (iParamMatch != aoParameter.Length)
          continue;
        listoMethod.Add (oMethod);
      }
      if (listoMethod.Count != 1)
      {
        string sError = "Method with Name '" + i_sMethodName + "' and BindingFlags '" + i_enBindingFlags + "' and Parameter Types '" + i_aoArgumentType?.ToString ("', '") + "'";
        if (listoMethod.Count == 0)
          throw new MissingMethodException (sError + " has no match.");
        else
          throw new AmbiguousMatchException (sError + " has " + listoMethod.Count + " matches.");
      }
      return listoMethod[0];
    }
    
    public static MethodInfo GetPrivateInstanceMethod (this Type i_oContainingType,
                                                            string i_sMethodName,
                                                            Type[] i_aoArgumentType,
                                                            bool i_bGeneric)
    {
      return GetMethod (i_oContainingType, i_sMethodName, BindingFlags.NonPublic | BindingFlags.Instance, i_aoArgumentType, i_bGeneric);
    }
    
    public static MethodInfo GetPublicInstanceMethod (this Type i_oContainingType,
                                                           string i_sMethodName,
                                                           Type[] i_aoArgumentType,
                                                           bool i_bGeneric)
    {
      return GetMethod (i_oContainingType, i_sMethodName, BindingFlags.Public | BindingFlags.Instance, i_aoArgumentType, i_bGeneric);
    }
    

    注意:
    i_aoArgumentType.ToString (..) 是另一种扩展方法。我想你可以猜到它的作用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多