我很难理解为什么在这个简单的例子中没有选择正确的过载.看看7.5.3.2更好的函数成员下的
C# 5 spec,它似乎应该能够选择非泛型的重载,但是对象参数似乎在某种程度上影响了我不理解的决定.我遇到的问题是我不能在不将参数转换为object的情况下调用非泛型版本的Foo(对象).从错误来看,它似乎不受支持,我希望有人可以了解原因.
public class A
{
public string Type { get { return "non-generic"; } }
}
public class A<T>
{
public string Type { get { return "generic"; } }
}
class Program
{
// (In reality only one of the variants below can be uncommented.)
static void Main(string[] args)
{
// This works fine and calls the generic overload as expected
A<string> x = Foo<string>("foobar");
// This results in a compile time error
// CS0029: Cannot implicitly convert type 'A<string>' to 'A'
A x = Foo("foobar");
// This works, but ends up calling the generic overload
var x = Foo("foobar");
// This works fine and calls the non-generic overload as expected
object a = "foobar";
var x = Foo(a);
// This works fine and calls the non-generic overload as expected
A x = Foo((object)"foobar");
// By using dynamic we're able to get rid of the compile-time error, but get a
// runtime exception.
// RuntimeBinderException: Cannot implicitly convert type 'A<string>' to 'A'
A x = Foo((dynamic)"foobar");
Console.WriteLine(x.Type);
Console.ReadLine();
}
private static A Foo(object x)
{
return new A();
}
private static A<T> Foo<T>(T x)
{
return new A<T>();
}
}
最佳答案 在
A x = Foo("foobar");
C#选择泛型方法,因为它比非泛型方法更具体,不需要转换.实际上,C#编译器创建了Foo方法的副本,并用具体类型字符串替换泛型类型参数T.重载决策在编译时执行.在运行时,将调用带有字符串参数的方法.在运行时不会创建通用开销.
请注意,分辨率仅考虑分配右侧的表达式.更具体地说,C#查看方法签名,即方法参数.方法的返回类型不属于其签名.
通用方法返回A< T>,但由于A< T>,因此返回A< T>.不是来自A,A< T>类型的结果.方法Foo< T>()的方法不能分配给类型A的x.对于具有动态的示例也是如此:没有来自A< T>的有效转换.到A.由于重载解析是在编译时完成的,因此动态无法解决您的问题. Dynamics正在运行时执行“工作”(即绑定).
同样,这不是您期望从确定使用哪个重载的方法的结果,而是传递给此方法的(静态)参数.
另一个有助于澄清事实的例子:
var x = Foo(5);
var y = Foo("hello");
在编译时,C#创建Foo方法的两个副本!一个用int和一个用string代替泛型类型参数T.在运行时没有发生转换;甚至不是拳击(不像Java那样将int包装成一个对象).