c# - 使用基类作为 IEnumerable<T> 的泛型

标签 c# generics inheritance c#-2.0 covariance

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

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

我们仍在使用 .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 */
}

当我尝试使用这个泛型方法时编译器报错

public void LoopThrough(IEnumerable<EntityBase> entityList)
{
    foreach(EntityBase entity in entityList) 
    {
        DoSomething(entity);  
    }
}

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

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

LoopThrough(entityList);

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

但是,我可以这样做:

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

Foo(new Entity());

还有这个:

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

CustomCollectionType<Entity> entityList;

Bar(entityList);

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

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

最佳答案

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

class Bowl<T> : IEnumerable<T> {}
class Apple : Fruit {}
...
void LoopThrough(IEnumerable<Fruit> fruits) ...

然后你打电话

Bowl<Apple> apples = whatever;
LoopThrough(apples);

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

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

Bowl<Apple> apples = whatever;
LoopThrough(apples.Cast<Fruit>());

要使其在 C# 2.0 中工作,自己实现 Cast 序列运算符。这只是几行代码。

请注意,在 C# 4.0 中,这样说仍然是不合法的:

Bowl<Fruit> fruits = new Bowl<Apples>();

因为你当然可以说:

fruits.Add(new Orange());

你只是把一个橙子放到一个只能装苹果的碗里。

关于c# - 使用基类作为 IEnumerable<T> 的泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8171549/

相关文章:

c# - 在 Visual Studio 中测试简单的 C# 代码表达式

c# - 我应该在 MVC 范例中将用户数据保存在哪里,以便可以在各个级别访问它?

c++ - 使用一个接口(interface),并告诉它所有的实现者_也将_继承自一个公共(public)基类

c# - 为什么不能使用 BindingList<TInherited> 作为采用 BindingList<T> 的方法的参数?

c# - 在 C# 字典中使用对象

c# - 如何调试 "Could not load file or assembly"运行时错误?

Java如何使方法参数接受子类类型和父类(super class)

java - 为什么不需要用泛型内部类参数化?

c# - 根据类型返回特定对象的通用工厂方法

inheritance - EF : select all entities of subclass (inheritance)