在计划我的计划时,我经常从这样的一系列思考开始:
足球队只是足球运动员的名单。因此,我应该用:
var football_team = new List<FootballPlayer>();
此列表的顺序代表球员在名单中列出的顺序。
但后来我意识到,除了球员名单之外,球队还有其他必须记录的属性。例如,本赛季的总得分、当前预算、队服颜色、string
代表团队的名称等。
那么我想:
好吧,一支足球队就像一份球员名单,但除此之外,它还有一个名字(一个string
)和总分(int
)。 .NET 没有提供用于存储足球队的类,因此我将创建自己的类。最相似和相关的现有结构是List<FootballPlayer>
,所以我将从它继承:
class FootballTeam : List<FootballPlayer>
{
public string TeamName;
public int RunningTotal
}
但事实证明指南说你不应该继承List<T> https://stackoverflow.com/a/5376343/1042555。我对这个指南在两个方面感到非常困惑。
Why not?
显然List以某种方式针对性能进行了优化 https://stackoverflow.com/a/5376358/1042555。为何如此?如果我扩展会导致什么性能问题List
?究竟会破坏什么?
我看到的另一个原因是List
由微软提供,我无法控制它,所以在公开“公共 API”之后,我无法稍后更改它 https://stackoverflow.com/questions/5376203/inherit-listt#comment6077237_5376343。但我很难理解这一点。什么是公共 API?我为什么要关心?如果我当前的项目没有也不可能有这个公共 API,我可以放心地忽略这个指南吗?如果我继承自List
and原来我需要一个公共API,我会遇到什么困难?
为什么它很重要?列表就是列表。可能会改变什么?我可能想改变什么?
最后,如果微软不想让我继承List
,他们为什么没有上课sealed
?
我还应该使用什么?
显然,对于自定义集合,微软提供了Collection
应该扩展的类而不是List
。但是这个类很简陋,没有太多有用的东西,such as AddRange https://stackoverflow.com/questions/1474863/addrange-to-a-collection, 例如。jvitor83 的回答 https://stackoverflow.com/a/12039943/1042555提供了该特定方法的性能原理,但是速度如何缓慢?AddRange
不比没有好AddRange
?
继承自Collection
比继承要多得多的工作List
,我看不出有什么好处。当然,微软不会无缘无故地告诉我做额外的工作,所以我不禁觉得我在某种程度上误解了某些东西,并继承了Collection
实际上不是解决我的问题的正确方法。
我见过诸如实施之类的建议IList
。就是不行。这是几十行样板代码,对我没有任何帮助。
最后,一些人建议将List
在某事上:
class FootballTeam
{
public List<FootballPlayer> Players;
}
这样做有两个问题:
它使我的代码变得不必要地冗长。我现在必须打电话my_team.Players.Count
而不是仅仅my_team.Count
。值得庆幸的是,使用 C#,我可以定义索引器以使索引透明,并转发内部的所有方法List
...但是代码太多了!所有这些工作我能得到什么?
简单来说这没有任何意义。足球队并没有“拥有”球员名单。它is球员名单。你不会说“John McFootballer 已加入 SomeTeam 的球员”。您说“约翰已加入 SomeTeam”。您不是向“字符串的字符”添加字母,而是向字符串添加字母。您不是将一本书添加到图书馆的图书中,而是将一本书添加到图书馆。
我意识到“幕后”发生的事情可以说是“将 X 添加到 Y 的内部列表中”,但这似乎是一种非常反直觉的思考世界的方式。
我的问题(总结)
表示数据结构的正确 C# 方式是什么?“逻辑上”(也就是说,“对于人类思维”)只是一个list
of things
有一些花哨的东西?
继承自List<T>
总是无法接受?什么时候可以接受?为什么/为什么不呢?程序员在决定是否继承时必须考虑什么List<T>
or not?