使用基类作为IEnumerable <T>的通用

mar*_*set 4 c# generics inheritance covariance c#-2.0

我对OOP一般,继承和多态,接口等有很好的理解.我遇到了一个奇怪的情况,我不明白为什么它根本不起作用...

编辑:好的,我发现协方差(或逆变?)可以解决这个问题,但至关重要

我们还在使用.NET 2.0

如何在不转向C#4.0的情况下解决这个问题?

情况就是这样.鉴于这两个类:

public class CustomCollectionType<T> : IEnumerable<T>
{
    /* Implementation here, not really important */
}

public class Entity : EntityBase
{
    /* Implentation here, not important */
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用这种通用方法时,编译器会抱怨

public void LoopThrough(IEnumerable<EntityBase> entityList)
{
    foreach(EntityBase entity in entityList) 
    {
        DoSomething(entity);  
    }
}
Run Code Online (Sandbox Code Playgroud)

并尝试以这种方式使用它:

CustomCollectionType<Entity> entityList;
/* Add items to list */

LoopThrough(entityList);
Run Code Online (Sandbox Code Playgroud)

错误说我无法转换CustomCollectionType<Entity>IEnumerable<EntityBase>.

但是,我可以这样做:

public void Foo(EntityBase entity)
{
    entity.DoSomething();
}

Foo(new Entity());
Run Code Online (Sandbox Code Playgroud)

还有这个 :

public void Bar(IEnumerable<Entity> entityList)
{ ... }

CustomCollectionType<Entity> entityList;

Bar(entityList);
Run Code Online (Sandbox Code Playgroud)

为什么我不能用层次结构中最高的类创建我的方法?这些类型显然是兼容的...我错过了什么?

编辑:我想解决这个问题,而不是以任何方式改变现有的类,所以在任何类中创建一个新方法,或实现一个额外的接口是不可能的.

Eri*_*ert 15

让我们考虑你的第一个案例.你有:

class Bowl<T> : IEnumerable<T> {}
class Apple : Fruit {}
...
void LoopThrough(IEnumerable<Fruit> fruits) ...
Run Code Online (Sandbox Code Playgroud)

你打电话

Bowl<Apple> apples = whatever;
LoopThrough(apples);
Run Code Online (Sandbox Code Playgroud)

这在C#3.0中失败了; 它在C#4.0中取得了成功,因为IEnumerable<T>它现在在T中是协变的; 一系列苹果可以用作一系列水果.

要使它在C#3.0中工作,您可以使用Cast序列运算符.

Bowl<Apple> apples = whatever;
LoopThrough(apples.Cast<Fruit>());
Run Code Online (Sandbox Code Playgroud)

要使它在C#2.0中工作,请自己实现Cast序列运算符.它只有几行代码.

请注意,在C#4.0中,说:

Bowl<Fruit> fruits = new Bowl<Apples>();
Run Code Online (Sandbox Code Playgroud)

因为你当然可以说:

fruits.Add(new Orange());
Run Code Online (Sandbox Code Playgroud)

你只需将橙子放入一个只能装苹果的碗里.