选择哪种C#方法重载?

时间:2015-10-01 16:13:58

标签: c# .net generics

为什么在两个重载都匹配时调用泛型方法?

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";
}

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

4 个答案:

答案 0 :(得分:37)

通过选择最具体的过载来解决过载问题。在这种情况下,method1<string>(string)method1(object)更具体,因此选择了过载。

section 7.4.2 of the C# specification中有详细信息。

如果要选择特定的重载,可以通过将参数显式地转换为所需的类型来实现。以下内容将调用method1(object)重载而不是通用的重载:

method1((object)"xyz"); 

有些情况下,编译器不知道要选择哪个重载,例如:

void method2(string x, object y);
void method2(object x, string y);

method2("xyz", "abc");

在这种情况下,编译器不知道要选择哪个重载,因为两个重载都没有明显好于另一个(它不知道哪个字符串隐式地向下转换为对象)。所以它会发出编译错误。

答案 1 :(得分:11)

C#总是会选择最具体的方法。

编译时

method1("xyz");

它将查找具有指定名称的所有方法,然后尝试匹配参数。编译器将选择最具体的方法,在这种情况下,它更喜欢

method1(string s)

method1<T>(T t) with T = string

最后

method1(object o)

请注意@ Erik对编译器无法决定的例子的优秀答案。

答案 2 :(得分:2)

因为您已经将T作为参数传递,所以您不需要输入method1<string>("xyz");就可以method1("xyz");,。。Net已经知道它是一个字符串。如果你有方法1那么这将是一个不同的故事。

此外,由于method1(object obj)不接受字符串作为参数,因此它首先支持泛型函数,它可以推断T.如果您要将method1(object obj)更改为method1(string obj)它首先会支持通用。

答案 3 :(得分:0)

方法重载如何工作

要查找调用方法的匹配签名,编译器将在虚拟表中从下至上搜索类型层次结构:

  • 首先在类层次结构中
  • 然后在界面层次结构中。

因为类在接口上占主导地位。

实际上,在成为接口类型之前,对象首先是类的类型。

非通用签名优先于通用,事实和事实优先于抽象,除非使用通用参数允许对更特殊类型的实例进行调用。

将理论应用于问题

此电话:

method1("xyz");

完美匹配:

void method1<T>(T t) { }

匹配之前:

void method1(object obj)

因为字符串是一个特殊的对象,可以将其用作通用参数以使其更加准确。

另一方面,如果您写:

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的类型(类型匹配)。

  • 第二次调用由于侧面转换(实现)而调用第二种方法。

  • 第三个调用调用第三个方法,因为指定了要作用于(模板)的通用参数。

  • 由于向下转换(多态性),第四个调用调用第四个方法。