【问题标题】:How do I distinguish between two methods with the same name and number of parameters in a generic class?如何区分泛型类中具有相同名称和参数数量的两个方法?
【发布时间】:2012-10-24 07:28:58
【问题描述】:

这是我的课:

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

    public void MyMethod(int a)
    {
    }
}

即使intMyClass 的泛型类型参数,我如何Invoke MyMethod(T) 使用Reflection

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

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

【问题讨论】:

  • GetMethods()[0].GetParameters()[0].ParameterType.IsGenericParameterGetMethods()[1].GetParameters()[0].ParameterType.IsGenericParameter 都为我返回 false。

标签: c# generics reflection


【解决方案1】:

修改后的答案

好的,所以我想我已经弄清楚为什么 IsGenericParameter 属性评估为 false 是因为您正在使用 &lt;T&gt; 的显式类型创建 MyClass 类型。

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

另外,根据我在 MSDN 中阅读的内容,我认为 ParameterType.IsGenericParameterType.IsGenericType property 只会评估为 true 每当您有像 MyMethod&lt;T&gt;()MyMethod(T a) 这样的方法时,&lt;T&gt; 的类型是从使用该类实例化的类型推断出来的。

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

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.

编辑

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

【讨论】:

  • 这是真的,但是 .. 现在通过反射 :)
  • 确实如此。但是我仅限于反思,因为我正在使用插件和多个 AppDomain 以及 Ninject 和疯狂。
  • 我认为这个答案stackoverflow.com/a/214106/1796930 提供了一个很好的扩展方法,应该可以解决问题。
  • @user1796930:参数名称不是我可以选择的。可能存在命名冲突,就像我的原始代码一样:/
  • 感谢您的修改 -- 感谢您花时间在这上面 -- Mike 也有一个简单的答案 -- 我认为他首先回答了,所以我接受了他,但我也发表了一个声明在我的问题中这样做是为了帮助未来的访问者。
【解决方案2】:

我能够做到这一点的唯一方法是将GetGenericTypeDefinitionIsGenericParameter 一起使用。在泛型类型定义中,一种方法会将参数上的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");
    }
}

【讨论】:

    猜你喜欢
    • 2020-11-26
    • 2014-11-10
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多