选择哪个c#方法重载
本文关键字:方法 重载 选择 | 更新日期: 2023-09-27 18:15:37
当两个重载都匹配时,为什么要调用泛型方法?
public static void method1(object obj)
{
Console.WriteLine("Object");
}
public static void method1<T>(T t)
{
Console.WriteLine("Type T");
}
public static void Main(String args[])
{
method1("xyz"); //Will print "Type T";
}
这里不应该有任何冲突,对吧?
通过选择最具体的重载来解决重载。在这种情况下,method1<string>(string)
比method1(object)
更具体,因此这是所选择的过载。
c#规范的7.4.2节中有详细的描述。
如果你想选择一个特定的重载,你可以通过显式地将参数转换为你想要的类型来实现。下面的代码将调用method1(object)
重载,而不是通用的:
method1((object)"xyz");
在某些情况下,编译器不知道选择哪个重载,例如:
void method2(string x, object y);
void method2(object x, string y);
method2("xyz", "abc");
在这种情况下,编译器不知道选择哪个重载,因为两个重载都不明显优于另一个(它不知道该隐式向下转换哪个字符串为object)。所以它会发出一个编译错误
c#总是会选择最具体的方法。
编译时method1("xyz");
将查找具有指定名称的所有方法,然后尝试匹配参数。编译器会选择最具体的方法,在这种情况下,它会选择
method1(string s)
/
method1<T>(T t) with T = string
最后
method1(object o)
请注意@Erik对于编译器无法决定的示例的出色回答。
因为你已经传入T作为参数,所以你不需要输入method1<string>("xyz");
,你可以直接输入method1("xyz");
, . net已经知道它是一个字符串。如果你有method1,那么情况就不同了。
另外,由于method1(object obj)
不接受字符串作为参数,它将优先考虑泛型函数,因为它可以推断t。如果你要将method1(object obj)
更改为method1(string obj)
,它将优先考虑它,然后是泛型函数。
方法重载如何工作
为了找到一个调用的方法的匹配签名,编译器在类型层次结构中从下到上搜索,也在虚表中搜索:
- 在类层次结构中的第一个,
- 在接口层次结构中。
因为类在接口上占上风。
实际上,对象在具有接口类型之前,首先具有类类型。
非泛型签名优先于泛型,因为事实优先于抽象,除非使用泛型参数允许对更专门化类型的实例进行调用。
将理论应用于问题
这叫:
method1("xyz");
完美搭配:
void method1<T>(T t) { }
匹配前:
void method1(object obj)
因为string是一个专门化的对象,它可以被用作更准确的泛型形参。
在另一边,如果你写:
void method1(string obj) { }
void method1<T>(T t) { }
第一个方法被称为
案例研究
var instance = new List<string>();
MyMethod(instance);
MyMethod((IEnumerable<string>) instance);
MyMethod<string>(instance);
MyMethod((object)instance);
void MyMethod<T>(List<T> instance) { }
void MyMethod<T>(IEnumerable<T> list) { }
void MyMethod<T>(T instance) { }
void MyMethod(object instance) { }
第一个调用调用第一个方法,因为实例是List的类型(类型匹配)。
第二个调用调用第二个方法,因为侧强制转换(实现)。
第三个调用调用第三个方法,因为指定了要操作的泛型参数(template)。
第四个调用调用第四个方法,因为向下强制转换(多态性)。