泛型类中的方法重载

时间:2012-05-30 20:14:58

标签: c# generics overloading

我正在使用包含泛型类中的以下重载方法的代码:

public class A<T>
{
    public void Process(T item) { /*impl*/ }
    public void Process(string item) { /*impl*/ }
}

当参数化string的类时,我是否失去了使用泛型参数调用版本的可能性?

var a = new A<string>();
a.Process(""); //Always calls the non-generic Process(string)

4 个答案:

答案 0 :(得分:14)

特定类型优先于泛型类型。

例如,这是我在LINQPad中测试过的。

void Main()
{
    new A<string>().Process("Hello");
}

public class A<T>
{
    public void Process(T item) { Console.WriteLine("T"); }
    public void Process(string item) { Console.WriteLine("string"); }
}

// Output: string

如果您在隐藏通用方法时遇到问题,那么您需要重新考虑一些事情。通过重载具有特定类型的泛型方法,您实际上是在说“如果需要,请使用泛型重载,但如果可以,请使用特定版本,因为它应该知道什么是最好的。

答案 1 :(得分:5)

是。这在C#规范第7.5.3节“重载解析”中有记录。

从7.5.3.6开始:

  

&#34;虽然声明的签名必须是唯一的,但类型参数的替换可能会产生相同的签名。在   在这种情况下,上面的超载解决方案的打破规则将会   选择最具体的成员。&#34;

在那里给出的例子表明,在下面的例子中,G<int>.F1的重载分辨率将选择非泛型

class G1<U>
{
    int F1(U u);
    int F1(int i);
}

这里适用的打破平局规则在7.5.3.2中概述,&#34;更好的功能成员&#34;:

  

如果参数类型序列为{P1,P2,...,PN}和{Q1,Q2,...,   QN}是等价的(即每个Pi都有一个身份转换为   相应的Qi),应用以下打破平局规则   命令,以确定更好的功能成员。

  • 如果MP是非泛型方法且MQ是泛型方法,则MP优于MQ。

答案 2 :(得分:5)

我发现了一种方法,但它有点cross。。由于泛型和重载在构建时得到解决,因此您可以定义一个通用方法:

public static CallerClass
{
    public static CallGenericOverload<T>(GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val); 
    }   

    //We can also make an extension method. 
    //We don't have to of course, it's just more comfortable this way.
    public static CallGenericOverloadExtension<T>(this GenericClass<T> cls, T val)
    {
        return cls.ProblemOverload(val);
    }

}

public GenericClass<T>
{
     public string ProblemOverload(T val)
     {
         return "ProblemOverload(T val)";
     }
     public string ProblemOverload(string val)
     {
         return "ProblemOverload(string val)";
     }
}

现在,如果我们执行以下操作:

var genClass = new GenericClass<string>();
Console.WriteLine(genClass.ProblemOverload("")); //output: ProblemOverload(string val)
Console.WriteLine(CallerClass.CallGenericOverload(genClass, "")); //output: ProblemOverload(T val)
Console.WriteLine(genClass.CallGenericOverloadExtension("")); //output: ProblemOverload(T val)

如果定义泛型类而不是泛型方法,则可以使用类似的技巧。重要的是,您转移到ProblemOverload的参数需要是T类型而不是调用中的string类型。毕竟,方法CallGenericOverload知道它在构建时获得T,因此它将绑定到接受参数的重载。它实际上会在运行时获得string并不重要。

答案 3 :(得分:0)

之前做过这个,我倾向于说“不”,但总会有更多知识渊博的人反驳。

如果内存服务,运行时编译器选择执行最强类型的重载。

<强>澄清

我的答案措辞严厉,我应该得到downvote。

OP问道,“当参数化类的字符串时,我是否失去了使用泛型参数调用版本的可能性?”我没有回答“不,你不能这样做,“但是那个”不,你不会失去使用泛型参数调用版本的能力。“

我应该更清楚。