泛型类中的方法重载
本文关键字:重载 方法 泛型类 | 更新日期: 2023-09-27 18:35:43
我正在使用在泛型类中包含以下重载方法的代码:
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)
特定类型优先于泛型类型。
例如,这是我在 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
如果您在隐藏泛型方法时遇到问题,那么您需要重新考虑一些事情。通过使用特定类型重载泛型方法,您实际上是在说,"如果需要,请使用泛型重载,但如果可以,请使用特定版本,因为它应该知道什么是最好的。
我刚刚发现了一种方法,但它有点斗鸡眼。由于泛型和重载是在生成时解决的,因此可以定义一个泛型方法:
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
并不重要。
是的。这记录在 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。
以前做过这个,我倾向于说"不",但总有更多的知识渊博的人会反驳。
如果内存可用,运行时编译器将选择要执行的最强类型的重载。
澄清
我的回答措辞糟糕,我应该投反对票。
OP 问道:"在参数化字符串类时,我是否失去了使用泛型参数调用版本的可能性?我不是在回答"不,你不能那样做",而是回答"不,你不会失去使用泛型参数调用版本的能力。
我应该更清楚。