从List<T>继承

50

如何最快地实现一个继承自List<T>的新类?

class Animal {}

class Animals : List<Animal> {} // (1)

我遇到的一个问题是:仅仅通过执行(1),我发现我没有从List<T>继承任何构造函数的好处。

最终,我希望Animals的行为非常类似于List<T>(例如可以构造,与Linq兼容)。但除此之外,我还想能够添加自己的自定义方法。


1
你发布的内容看起来对我来说很不错! - Stuart
你上面的代码可以实现这个功能。你需要实现任何构造函数,并调用基类 (List<Animal>) 上的相关构造函数。你可以在 Animals 类中创建任何自定义方法。 - detaylor
1
可能是C#:List <T>继承问题的重复 - George Stocker
6个回答

52
如果您想创建一个公开的动物集合,不应继承自List<T>,而应该继承自Collection<T>,并在类名后使用后缀Collection。例如:AnimalCollection : Collection<Animal>
这得到了框架设计指南的支持,更具体地说: 请勿在公共API中使用ArrayListList<T>HashtableDictionary<K,V>。改为使用Collection<T>ReadOnlyCollection<T>KeyedCollection<K,T>或CollectionBase子类型。请注意,泛型集合仅受Framework版本2.0及以上支持。

90
我不明白为什么我应该遵循这个指南。 - R. Martinho Fernandes
8
@Martinho Fernandes,这是像其他指南一样的“指导方针”,但如果您在公共API中提供了一个打字集合,您可以在将来的版本中更改它,因为这是您的类型。如果您直接使用List<T>,那么就没有这个机会了。 - João Angelo
8
考虑使用接口,例如ICollection<T>、IEnumerable<T>、IDictionary<TKey,TValue>等。 - chillitom
8
也许是因为你无法覆盖Add/Remove方法,而使用Collection<T>则可以。顺便说一句,我更喜欢使用内部的List<T>来实现IList<T>ICollection<T>,而不是继承自Collection<T> - digEmAll
1
@TomBeech,Collection<T> 实现了 IEnumerableIEnumerable<T>。使用 List<T> 能得到什么,而使用 Collection<T> 得不到什么? - João Angelo
显示剩余8条评论

32

构造函数不会随着类一起继承。您需要重新实现所需的构造函数。

public class AnimalsCollection : List<Animal>
{
     public AnimalsCollection(IEnumerable<Animal> animals) : base(animals) {} 
}

13
投票者想表达为什么?他问为什么他“没有任何构造函数”,这就是我的回答的原因。如果你不同意,何不留下一些反馈意见呢? - Anderson Imes
5
原文:Same reason as for Tokk. But this shows once again why anonymous downvotes suck: It’s just not helping.翻译:与Tokk一样的原因。但这再次显示匿名的踩并没有帮助:它只会让事情变得更糟。 - Konrad Rudolph
1
请看: stackoverflow.com/questions/3748931/ stackoverflow.com/questions/898152/ stackoverflow.com/questions/794679/ stackoverflow.com/questions/5207459/ stackoverflow.com/questions/2136213/ stackoverflow.com/questions/349904 stackoverflow.com/questions/1257214 - George Stocker
2
@George Stocker:这仍然不是OP的问题。在回答实际问题之前,我们必须分析每个人的方法,这让我有点烦恼。知道构造函数不会被继承本身就是一件有用的事情。 - Anderson Imes
2
@Anderson 是的,但这里的普遍情绪并不是给问题提出者一条鱼,而是教他们如何钓鱼。 话虽如此,我不会对这个答案进行投票,并且我只能再次说匿名投票很糟糕。 - Konrad Rudolph
显示剩余3条评论

14

继承自 List<T> 不被建议。主要是因为 List 从来没有被设计用于扩展,而是为了获得更好的性能。

如果你想创建自己特定的集合,你应该继承自 Collection<T>。在你的情况下,应该这样写:

class Animals : Collection<Animal> {}

2
我按照您的建议进行了操作,并从Collection<MyClass>继承。但是在某些地方遇到了问题,例如Collection<T>不支持SortFindFindAll等许多非常有用的方法。我必须将其更改为从List<MyClass>继承。有什么我可以做的吗..? - shashwat
4
它没有那些方法,是因为“Collection”类应该是用于表示任何一组物品的通用类。例如,数学集合没有特定的顺序,也不能排序。“Find”如果元素不唯一,则可能会产生歧义。这两种情况都应该是“Collection”可以用于的情况之一,因此它不能包括“Sort”和“Find”而失去其普适性。尽管可能应该有一个“ListCollection : Collection”,因为似乎那是人们最常用它的方式。 - Superbest

6
记住,从List继承并不如你所需的那样功能齐全,很多成员都不是虚拟的,因此覆盖基本实现的唯一方法是使用new语法(而不是override)来屏蔽它。
如果您需要开始在标准列表操作上公开自定义行为,我建议在一个类型上实现所有列表接口,该类型仅使用内部列表进行实际存储。
这在很大程度上取决于您的最终要求。

我按照您的建议进行了操作,并从Collection<MyClass>继承。但是在某些地方遇到了问题,例如Collection<T>不支持SortFindFindAll等许多非常有用的方法。我必须将其更改为从List<MyClass>继承。有什么我可以做的吗..? - shashwat
3
“Sort”、“Find”和“FindAll”等操作可以基于LINQ对IEnumerable<T>进行实现,因此这不是一个问题。 - Earth Engine

4
class Animals : List<Animal> {}

看起来这是最好的方法,因为您可以在定义后立即使用它。

所以我建议您的问题标题:Inherit List<T> ;-)


5
没有给你点踩,但通常情况下,你不应该从具体的集合类中继承(实际上它们应该被声明为“sealed”)。更好的方式是实现一个接口或者继承一个抽象基类(比如 Collection<T>)。请注意,这些方法并没有改变原文的意思。 - Konrad Rudolph
1
同意Konrad的观点。继承自List<T>是你不应该做的事情之一。这个问题在Stack Overflow上已经被讨论了数百次。 - George Stocker
请参见以下程序相关内容链接: https://dev59.com/Wm865IYBdhLWcg3wkfcW https://dev59.com/VkfRa4cB1Zd3GeqP_LL8 https://dev59.com/eUfRa4cB1Zd3GeqP8V2j http://stackoverflow.com/questions/5207459/inheriting-from-listt-in-net-vb-or-c https://dev59.com/QUvSa4cB1Zd3GeqPfY5P#2136235 https://dev59.com/kEXRa4cB1Zd3GeqPv_SD http://stackoverflow.com/questions/1257214/ - George Stocker

4

使用集合初始化语法或使用Linq扩展方法不需要继承List

只需实现IEnumerable接口并且添加Add方法即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接