泛型类中的方法重载

Posted

技术标签:

【中文标题】泛型类中的方法重载【英文标题】:Method overloading in generic class 【发布时间】:2012-06-05 02:51:26 【问题描述】:

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

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)

【问题讨论】:

【参考方案1】:

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

例如,这是我在 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

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

【讨论】:

所以我认为答案是肯定的? 另见:blogs.msdn.com/b/ericlippert/archive/2009/07/30/…【参考方案2】:

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

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】:

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

从 7.5.3.6 开始:

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

其中给出的示例指出,在以下情况下,G&lt;int&gt;.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。

【讨论】:

喜欢答案,不喜欢规则...不过幸运的是你可以显式调用方法【参考方案4】:

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

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

澄清

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

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

我应该更清楚。

【讨论】:

其实这个是在编译时解决的。运行时不选择任何东西。 说得好。我以为是这样,但这就是我在咳嗽糖浆的影响下发帖的结果。 :-/ 嗯,重新。您的澄清:实际上您确实失去了使用通用参数调用 te 版本的能力(如果参数是字符串类型,这是 OP 要求的)。 如果你像我所展示的那样明确地称呼它......不管是否有止咳糖浆......但它确实有帮助:P

以上是关于泛型类中的方法重载的主要内容,如果未能解决你的问题,请参考以下文章

c ++继承:基类中的2次重载运算符+在派生类中无法正常工作

c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?

泛型方法或泛型类中的方法是内部调用PInvoke 或是在 COM 导入类中定义的。

泛型类中的静态方法?

泛型还是只使用重载?

您可以使用泛型进行方法重载并且只更改方法签名的泛型类型吗?