Generics IEnumerable上的类型推断<;T>;

Generics IEnumerable上的类型推断<;T>;,generics,resolution,covariance,Generics,Resolution,Covariance,在stack overflow上已经有一些关于这类事情的帖子,但并不完全相同——因此,如果这是已经回答过的问题,请提前道歉 为什么这不起作用: public class MyBase { } public class MyUtils { public bool Foo<T> (T myObject) { return true; } public bool Foo (MyBase myBaseObject) { return false; } public

在stack overflow上已经有一些关于这类事情的帖子,但并不完全相同——因此,如果这是已经回答过的问题,请提前道歉

为什么这不起作用:

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));
        }
    }
}
为什么它不叫专门的MyBase版本呢?如果我直接调用Foo(newmybase()),它将正确地推断要进行的调用。这是因为C#3中的集合缺乏协方差,还是我太傻了,做得不对

谢谢

Isaac

根据C#规范(7.4.3.2),非通用方法优于通用方法,因此应选择非通用方法

但是,我认为在你的例子中,泛型方法是被选中的,因为它是在泛型调用上下文(“foreach”循环)中调用的。

它不调用“专用”方法,因为编译器选择在编译程序时调用哪个方法(在本例中,是
Go
函数),当它运行时就不会了

当编译器编译
Go
函数时,它拥有的唯一信息是存在
T
类型的对象。它不知道您可能在以后的某个时间点向它提供类型为
MyBase
的对象。它唯一的选择是选择
Foo
重载,因此它将其烘焙到编译程序中

如果希望应用程序在运行时选择重载,并在应用程序运行时通过查看对象来选择最佳重载,则称为“动态调度”,并且仅由Ruby、Python、PHP等动态语言使用

C#3是完全静态的,不支持此功能。如果希望类型以这种方式工作,则必须在代码中编写if语句来检查类型。 另一方面,C#4有一些动态支持。如果您是用C#4编写此代码,则可以按如下方式声明“Go”函数:

 public void Go<T> (IEnumerable<dynamic> items)
public void Go(IEnumerable items)

然后,它将在运行时使用动态调度来选择调用哪个重载,并将调用专门化的重载以获取
MyBase

在编译时完成重载解析,在编译时,每个“项”都是类型T,它不知道其中任何一个是专门为MyBase编写的。@meandmycode-你应该把它作为一个答案发布(带有链接)谢谢。它在编译时不知道它是MyBase类型的吗?因为我要传递的集合被键入MyBase?Orion-谢谢你的回答。就在几天前,我似乎得出了同样的结论。。。谢谢你的确认:)
 public void Go<T> (IEnumerable<dynamic> items)