请考虑以下代码:
public class Tests
{
public void Test()
{
Assert.AreEqual("Int", DoSomething(1));
}
public static string DoSomething<T>(T value)
{
return "Generic";
}
public static string DoSomething(int value)
{
return "Int";
}
}
正如预期的那样,将调用非泛型的DoSomething方法。现在考虑以下修改:
public class Tests
{
public void Test()
{
Assert.AreEqual("Int", DoSomething(1));
}
public static string DoSomething<T>(T value)
{
return "Generic";
}
public static string DoSomething<T>(int value)
{
return "Int";
}
}
我唯一改变的是将T类型参数添加到第二个重载,从而使其成为通用的。请注意,不使用type参数。
该修改导致调用第一个DoSomething方法。为什么?编译器具有选择第二种方法所需的所有信息。
您能否解释为什么,甚至更好地指出解释此行为的C#规范部分?
答案 0 :(得分:10)
在您的调用中,您没有指定类型参数 - 因此编译器必须推断T
的类型。它不能为您的第二个方法执行此操作,因为声明的参数中从未提及type参数。因此,该重载不适用,并被忽略。
如果您为通话指定了类型参数,例如
中的任何一个DoSomething<int>(1)
DoSomething<object>(1)
DoSomething<string>(1)
...然后在所有情况下都会调用第二个重载。
在构建候选方法集时,从C#5规范的第7.6.5.1节(方法调用):
- 如果F是通用的且M没有类型参数列表,则F是以下情况的候选者:
- 类型推断(第7.5.2节)成功,推断出调用的类型参数列表,
- 一旦推断的类型参数替换相应的方法类型参数,F的参数列表中的所有构造类型都满足其约束(§4.4.4),并且F的参数列表适用于A(§) 7.5.3.1)。
由于类型推断没有成功,第二种方法不在候选集中,所以当我们实现真正的重载解析时,该集只有一个方法(第一个)。
答案 1 :(得分:-1)
编译器无法确定调用DoSomething(1)中的模式类型,但如果指定[int],则会选择另一种方法。