如何区分泛型类中具有相同名称和参数数量的两种方法?

时间:2012-11-04 02:41:34

标签: c# generics reflection

这是我的班级:

public class MyClass<T>
{
    public void MyMethod(T a)
    {
    }

    public void MyMethod(int a)
    {
    }
}

即使InvokeMyMethod(T)的通用类型参数,我如何Reflection int使用MyClass

这是一个单一的声明(可能效率低下,但我喜欢简洁):

var mc = new MyClass<int>();

typeof(MyClass<int>).GetMethods().ElementAt(
    typeof(MyClass<int>).
    GetGenericTypeDefinition().
    GetMethods().ToList().FindIndex(m =>
        m.Name.Equals("MyMethod") && 
        m.GetParameters().Count() == 1 &&
        m.GetParameters()[0].ParameterType.IsGenericParameter)
    ).Invoke(mc, new object[] { 1 });

2 个答案:

答案 0 :(得分:4)

修订答案

好的,所以我想我已经弄清楚为什么IsGenericParameter属性评估为false是因为你创建的MyClass类型具有<T>的显式类型。

由于编译器新建了a参数的类型(从类的实例化推断),我猜测编译器将参数视为非泛型类型。

另外,根据我在MSDN上阅读的内容,我认为ParameterType.IsGenericParameterType.IsGenericType property只能评估为真 只要你有MyMethod<T>()MyMethod(T a)之类的方法,<T>的类型就会从使用类实例化的类型中推断出来。

这是一个演示这个的小程序:

using System;
using System.Linq;
using System.Reflection;

namespace GenericParametersViaReflectionTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // Note: we're using the type without specifying a type for <T>.
            var classType = typeof(MyClass<>);

            foreach (MethodInfo method in classType.GetMembers()
                .Where(method => method.Name == "MyMethod"))
            {
                // Iterate through each parameter of the method
                foreach (var param in method.GetParameters())
                {
                    // For generic methods, the name will be "T" and the FullName
                    // will be null; you can use which ever check you prefer.
                    if (param.ParameterType.Name == "T"
                        || param.ParameterType.FullName == null)
                        Console.WriteLine("We found our generic method!");
                    else
                        Console.WriteLine("We found the non-generic method:");

                    Console.WriteLine("Method Name: {0}", method.Name);
                    Console.WriteLine("Parameter Name: {0}", param.Name);
                    Console.WriteLine("Type: {0}", param.ParameterType.Name);
                    Console.WriteLine("Type Full Name: {0}",
                        param.ParameterType.FullName ?? "null");
                    Console.WriteLine("");
                }   
            }
            Console.Read();
        }
    }
    public class MyClass<T>
    {
        public void MyMethod(T a) { }
        public void MyMethod(int a) { }
    }
}

我们最终得到的结果是:

  

我们找到了或通用方法!
  方法名称:MyMethod
  参数名称:a
  类型:T
  输入全名:null

     

我们发现了非通用方法:
  方法名称:MyMethod
  参数名称:a
  类型:Int32
  输入全名:System.Int32

如果您需要使用特定类型创建类的实例,您可能会发现Activator.CreateInstance class也很有用。


原始答案

我认为如果你传入一个与明确设置的方法之一匹配的相同数据类型的参数(例如Int32方法),那么编译器会自动选择那个接受泛型参数的参数。否则,编译器将选择泛型方法。

但是,如果您希望能够控制选择哪个方法,则可以修改每个方法以使用不同的参数名称,同时保持相同的签名,如下所示:

public class MyClass<T>
{
    public void MyMethod(T genericA) {}
    public void MyMethod(int intA) {}
}

然后,使用named parameters,您可以显式调用所需的方法,如下所示:

var foo = new MyClass<int>();
foo.MyMethod(genericA: 24); // This will call the "MyMethod" that only accepts <T>.
foo.MyMethod(intA: 19); // This will call the "MyMethod" that only accepts integers.

<强> 修改

出于某种原因,在我的原始答案中,我错过了你提到使用反射的部分,但看起来我的原始答案可以与这些其他答案相结合,为你提供一个可行的解决方案:

答案 1 :(得分:3)

我能够做到这一点的唯一方法是将GetGenericTypeDefinitionIsGenericParameter一起使用。在泛型类型定义中,一个方法将IsGenericParameter设置为参数的true。但是,对于封闭类型,没有任何参数会将此视为真。然后,您不能使用泛型类型定义中的MethodInfo来调用方法,因此我存储了索引并使用它来查找封闭类型中的相应MethodInfo

public class Program
{
    public static void Main(string[] args)
    {
        bool invokeGeneric = true;
        MyClass<int> b = new MyClass<int>();
        var type = b.GetType().GetGenericTypeDefinition();
        int index = 0;
        foreach(var mi in type.GetMethods().Where(mi => mi.Name == "MyMethod"))
        {
            if (mi.GetParameters()[0].ParameterType.IsGenericParameter == invokeGeneric)
            {
                break;
            }
            index++;
        }

        var method = b.GetType().GetMethods().Where(mi => mi.Name == "MyMethod").ElementAt(index);
        method.Invoke(b, new object[] { 1 });
    }
}

public class MyClass<T>
{
    public void MyMethod(T a)
    {
        Console.WriteLine("In generic method");
    }

    public void MyMethod(int a)
    {
        Console.WriteLine("In non-generic method");
    }
}