【问题标题】:A list holding generic-inherited classes包含泛型继承类的列表
【发布时间】:2014-10-21 14:39:54
【问题描述】:

假设我有一个通用抽象类:

ClassA<T> where T: ClassB

现在

public class ClassC: ClassB

public class NewClass: ClassA<ClassC>

我可以使用默认构造函数创建NewClass 对象,但我找不到将其保存在更通用ClassA&lt;T&gt; 对象的通用集合中的方法。 列表定义为

List<ClassA<ClassB>>

无法容纳NewClass 对象。我想在同一个集合中保留不同的派生类型。有没有办法在 C# 中做到这一点? 另外,如果可能的话,我想避免使用接口和虚拟调用。

【问题讨论】:

  • 为什么要避免接口?我宁愿避免子类化,更喜欢组合而不是继承en.wikipedia.org/wiki/Composition_over_inheritance
  • @DennisTraub 我正在设计一个游戏引擎的原型,而接口调用对于这个目的来说太昂贵了。
  • 我假设使用动态或无类型列表已经过时了...为什么要使用所有不同的通用基本类型?
  • @Tarec :接口调用比普通实例调用更昂贵,但如果您处于这种思维模式,实例调用比静态调用更昂贵。静态调用比访问编译时常量更昂贵。那么你应该创建一个编译时常量游戏吗?当然不是!接口调用不太可能对您的性能产​​生任何可衡量的影响。

标签: c# list generics inheritance


【解决方案1】:

你的问题远比你的事情简单,它与parameter variance有关。 查看这些非常简单的类:

public class Base {}

public class Derived : Base {}

List&lt;Derived&gt;不是List&lt;Base&gt;,这正是您面临的问题。这是为什么?因为您可以将new Base() 添加到后者,但不能添加到前者。同样,在您的情况下,NewClassClassA&lt;ClassC&gt;ClassC 继承自 ClassB,但 NewClass不是ClassA&lt;ClassB&gt;

您很可能必须重新设计您的架构,可能需要使用接口(您认为合适的接口可以是协变的或逆变的)。

编辑:一些实现思路

例如,您可以定义协变接口接口:

public interface IClassA<out T> where T : ClassB

然后List&lt;IClass&lt;ClassB&gt;&gt; 将能够持有NewClass

或者您可以让ClassA&lt;T&gt; 继承自非泛型基类ClassA

public class ClassA
public class ClassA<T> : ClassA  where T : ClassB

然后您可以将您的NewClass 存储在List&lt;ClassA&gt;

【讨论】:

  • 我知道,但在 f.e.在 Java 中有允许为泛型集合定义子类的通配符,我正在 C# 中寻找类似的解决方案。你对重新设计是正确的——如果我没有选择的话,我会这样做。
  • @Tarec 在概念级别上不是类型安全的。这不是 C# 有没有特性的问题。如果不删除静态类型,就无法安全地将 List 视为协变。
  • 谢谢你们,讨论让我头脑清醒了一点,我一开始似乎确实有一些不正确的概念。
  • Servy 是对的,将集合类视为协变从根本上是错误的,因为您可以向它们添加项目。这与拥有协变数组相同,这是一个经常困扰开发人员的设计缺陷(现在我们几乎从未使用过“裸”数组,但仍然如此)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-05-14
  • 2020-10-08
  • 2018-09-27
  • 2015-09-15
  • 2018-08-01
  • 1970-01-01
相关资源
最近更新 更多