10

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

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

4 回答 4

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

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

于 2012-05-30T20:20:05.140 回答
5

是的。这记录在 C# 规范的第 7.5.3 节,重载决议中。

从 7.5.3.6 开始:

“虽然声明的签名必须是唯一的,但类型参数的替换可能会导致相同的签名。在这种情况下,上述重载决议的平局规则将选择最具体的成员。”

那里给出的示例指出,在下面的情况下,重载解析G<int>.F1将选择非泛型

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

7.5.3.2,“更好的函数成员”中概述了适用于此的平局规则:

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

  • 如果 MP 是非泛型方法而 MQ 是泛型方法,则 MP 优于 MQ。
于 2012-05-30T20:26:25.523 回答
5

我刚刚发现了一种方法,但有点眼花缭乱。因为泛型和重载在构建时得到解决,你可以定义一个泛型方法:

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在构建时得到 a,因此它将绑定到接受参数的重载。它实际上会string在运行时得到 a 并不重要。

于 2012-05-30T20:26:34.697 回答
0

以前这样做过,我倾向于说“不”,但总有更多有见识的人会反对。

如果内存够用,运行时编译器会选择最强类型的重载来执行。

澄清

我的回答措辞不好,我应该投反对票。

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

我应该更清楚。

于 2012-05-30T20:22:19.443 回答