关于此类事情已经有一些关于堆栈溢出的帖子但不完全相同 - 所以如果这已经得到解答,请提前道歉。
为什么这不起作用:
public class MyBase { }
public class MyUtils
{
public bool Foo<T> (T myObject) { return true; }
public bool Foo (MyBase myBaseObject) { return false; }
public void Go<T> (IEnumerable<T> items)
{
foreach (var item in items)
{
// this test fails
Assert.IsFalse (Foo (item));
}
}
}
如果我上面调用Go()并传入一堆MyBase对象,每次调用Foo都会调用泛型Foo(),返回true。
new MyUtils ().Go (new MyBase[] { new MyBase (), new MyBase () });
为什么不调用专门的MyBase版本呢?如果我直接调用Foo(new MyBase()),它会正确地推断出make的调用。这是因为C#3中的集合缺乏协方差,还是我只是愚蠢而没有正确地做到这一点?
谢谢!
艾萨克
答案 0 :(得分:1)
它不会调用“专用”的,因为当程序(在本例中是Go
函数)编译时,编译器会选择调用哪个方法,< em> not 当它运行时。
当编译器正在编译Go
函数时,它所拥有的唯一信息是存在类型为T
的对象。它不知道您可能在稍后的某个时间点为其提供MyBase
类型的对象。它唯一的选择是选择Foo<T>
重载,因此它将其加入到已编译的程序中。
如果您希望应用程序在运行时选择重载,并通过在应用程序运行时查看对象来选择最佳重载,那称为“动态分派”,并且仅由Ruby等动态语言使用, Python,PHP等
C#3是完全静态的,不支持此功能。如果您希望它以这种方式工作,您必须在代码中编写if语句来检查类型。 另一方面,C#4有一些动态支持。如果您在C#4中编写此代码,则可以按如下方式声明“Go”函数:
public void Go<T> (IEnumerable<dynamic> items)
然后它会在运行时使用动态调度来选择调用哪个重载,并调用过载专用于MyBase
答案 1 :(得分:0)
根据C#规范(7.4.3.2),非泛型方法优于通用方法,因此应选择它。
但是,我认为在您的情况下会选择泛型,因为它是在通用调用上下文中调用的(“foreach”循环)。