选择哪个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";
}

这里不应该有任何冲突,对吧?

选择哪个c#方法重载

通过选择最具体的重载来解决重载。在这种情况下,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)。

  • 第四个调用调用第四个方法,因为向下强制转换(多态性)。