泛型类中的方法重载
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<int>.F1
的重载解析将选择非泛型
class G1<U>
int F1(U u);
int F1(int i);
7.5.3.2,“更好的函数成员”中概述了适用于此的平局规则:
如果 MP 是非泛型方法,MQ 是泛型方法,那么 MP 优于 MQ。如果参数类型序列 P1, P2, ..., PN 和 Q1, Q2, ..., QN 是等价的(即每个 Pi 都有一个到 相应的 Qi),应用以下平局规则,在 顺序,以确定更好的函数成员。
【讨论】:
喜欢答案,不喜欢规则...不过幸运的是你可以显式调用方法【参考方案4】:之前做过这件事,我倾向于说“不”,但总有更多有见识的人会反对。
如果内存够用,runtime 编译器会选择最强类型的重载来执行。
澄清
我的回答措辞不好,我应该投反对票。
OP 问道,“当为字符串参数化类时,我会失去使用泛型参数调用版本的可能性吗?”我没有回答“不,你不能那样做” 但是“不,您不会失去使用通用参数调用版本的能力。”
我应该更清楚。
【讨论】:
其实这个是在编译时解决的。运行时不选择任何东西。 说得好。我以为是这样,但这就是我在咳嗽糖浆的影响下发帖的结果。 :-/ 嗯,重新。您的澄清:实际上您确实失去了使用通用参数调用 te 版本的能力(如果参数是字符串类型,这是 OP 要求的)。 如果你像我所展示的那样明确地称呼它......不管是否有止咳糖浆......但它确实有帮助:P以上是关于泛型类中的方法重载的主要内容,如果未能解决你的问题,请参考以下文章
c ++继承:基类中的2次重载运算符+在派生类中无法正常工作
c#中泛型类构造函数重载赋值时为啥不接受null?对其赋空值应给怎么做?