C#无法从IEnumerable <Base>转换为IEnumerable <Derived>

maf*_*afu 5 c# collections ienumerable inheritance

我最近在尝试将AddRange(IEnumerable)添加到List时遇到了麻烦.可能是一个经典问题,但我还没有真正得到它.

我知道期望List参数的方法不满足于List,因为他们可能会尝试向List添加Base,这显然是不可能的.

但是,如果我得到正确的,因为IEnumerables本身不能改变,它应该在这种情况下工作.

我想到的代码看起来像这样:

class Foo
{
}

class Bar : Foo
{
}

class FooCol
{
    private List<Foo> m_Foos = new List<Foo> ();

    public void AddRange1(IEnumerable<Foo> foos)
    {
        m_Foos.AddRange (foos); // does work
    }

    public void AddRange2<T>(IEnumerable<T> foos) where T : Foo
    {
        m_Foos.AddRange (foos); // does not work
    }
}

class Program
{
    static void Main(string[] args)
    {
        FooCol fooCol = new FooCol ();

        List<Foo> foos = new List<Foo> ();
        List<Bar> bars = new List<Bar> ();

        fooCol.AddRange1 (foos); // does work
        fooCol.AddRange1 (bars); // does not work

        fooCol.AddRange2 (foos); // does work
        fooCol.AddRange2 (bars); // does work
    }
}
Run Code Online (Sandbox Code Playgroud)

我试图在AddRange2方法中向编译器传递一个提示,但这只是问题所在.

我的思维方式有缺陷吗?这是语言的限制还是设计?

IIRC,Java 1.5中添加了对此类操作的支持,所以也许它将来会在某个时候被添加到C#中......

Mar*_*ell 18

这是协方差,将在C#4.0/.NET 4.0中修复.目前,通用选项是最好的答案(对于IEnumerable<T>- 不是IList<T>).

但是在通用方法中,你必须考虑到T.您也可以使用Cast<T>OfType<T>使用LINQ来实现类似的功能.