3

这是我的课:

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

    public void MyMethod(int a)
    {
    }
}

即使是泛型类型参数,我将如何Invoke MyMethod(T)使用?ReflectionintMyClass

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

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 });
4

2 回答 2

4

修订答案

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

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

另外,根据我在 MSDN 中阅读的内容,我认为ParameterType.IsGenericParameterType.IsGenericType 属性MyMethod<T>()只有在你有类似vs.的方法时才会评估为 true MyMethod(T a),其中类型 for<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 类也很有用。


原始答案

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

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

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

然后,使用命名参数,您可以显式调用所需的方法,如下所示:

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.

编辑

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

于 2012-11-04T03:11:18.220 回答
3

我能够做到这一点的唯一方法是使用GetGenericTypeDefinitionwith IsGenericParameter。在泛型类型定义中,一种方法将IsGenericParameter在参数上设置为 true。但是,对于封闭类型,没有任何参数将其设为 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");
    }
}
于 2012-11-04T05:31:05.080 回答