在规划我的程序时,我经常以这样的思路开始:
A football team is just a list of football players. Therefore, I should represent it with:
var football_team = new List<FootballPlayer>();
The ordering of this list represent the order in which the players are listed in the roster.
但后来我意识到,除了球员名单之外,球队还有其他一些必须记录的属性。比如本赛季跑分总分,当前预算,统一颜色,一个
string
代表队名等。那么我想:
Okay, a football team is just like a list of players, but additionally, it has a name (a
string
) and a running total of scores (anint
). .NET does not provide a class for storing football teams, so I will make my own class. The most similar and relevant existing structure isList<FootballPlayer>
, so I will inherit from it:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
但事实证明,a guideline says you shouldn't inherit from
List<T>
.我对这个指南在两个方面感到非常困惑。为什么不?
显然
List
is somehow optimized for performance .为何如此?如果我扩展 List
会导致什么性能问题?究竟会破什么?我见过的另一个原因是
List
由微软提供,我无法控制,所以 I cannot change it later, after exposing a "public API" .但我很难理解这一点。什么是公共(public) API,我为什么要关心?如果我当前的项目没有也不太可能有这个公共(public) API,我可以安全地忽略这个指南吗?如果我确实继承自 List
事实证明我需要一个公共(public) API,我会有什么困难?为什么这很重要?列表是一个列表。什么可能改变?我可能想要改变什么?
最后,如果微软不想让我继承
List
,他们为什么不上课sealed
?我还应该使用什么?
显然,对于自定义集合,Microsoft 提供了一个
Collection
应该扩展的类而不是 List
.但是这个类很空,有用的东西不多,such as AddRange
, 例如。 jvitor83's answer为该特定方法提供了性能原理,但速度如何慢 AddRange
不比没有好 AddRange
?继承自
Collection
比从 List
继承更多的工作,我看不出有什么好处。微软肯定不会无缘无故地告诉我做额外的工作,所以我不禁觉得我不知何故误解了一些东西,并继承了Collection
实际上不是我的问题的正确解决方案。我已经看到了诸如实现
IList
之类的建议。 .就是不行。这是几十行样板代码,对我没有任何帮助。最后,有些人建议包装
List
在某事:class FootballTeam
{
public List<FootballPlayer> Players;
}
这有两个问题:
my_team.Players.Count
而不仅仅是 my_team.Count
.值得庆幸的是,使用 C# 我可以定义索引器使索引透明,并转发内部 List
的所有方法。 ...但这是很多代码!所有这些工作我能得到什么? 我意识到“幕后”发生的事情可以说是“将 X 添加到 Y 的内部列表中”,但这似乎是一种非常反直觉的思考世界的方式。
我的问题(总结)
表示数据结构的正确 C# 方式是什么,“逻辑上”(也就是说,“对人的思想”)只是一个
list
的 things
有一些花里胡哨?继承自
List<T>
总是不能接受?什么时候可以接受?为什么/为什么不?程序员在决定是否从 List<T>
继承时必须考虑什么或不?
最佳答案
这里有一些很好的答案。我会向他们补充以下几点。
What is the correct C# way of representing a data structure, which, "logically" (that is to say, "to the human mind") is just a list of things with a few bells and whistles?
请任何十名熟悉足球存在的非计算机程序员填写空白:
A football team is a particular kind of _____
有没有人说“有一些花里胡哨的足球运动员名单”,或者他们都说“运动队”或“俱乐部”或“组织”?你认为一支足球队是一种特殊类型的球员名单,这是你人类的思想,而且只有你的人类思想。
List<T>
是一种机制。足球队是一个业务对象——也就是说,一个代表程序业务领域中的一些概念的对象。不要混合这些!足球队是一种团队;它有一个名册,名册是一份球员名单。名册不是特定类型的球员名单。名册是球员名单。所以创建一个名为 Roster
的属性那是一个 List<Player>
.并使它ReadOnlyList<Player>
除非你相信每个了解足球队的人都可以从名单中删除球员。Is inheriting from
List<T>
always unacceptable?
谁不能接受?我?不。
When is it acceptable?
当您构建扩展
List<T>
的机制时机制。What must a programmer consider, when deciding whether to inherit from
List<T>
or not?
我是在构建机制还是业务对象?
But that's a lot of code! What do I get for all that work?
您花了更多时间输入您的问题,否则您需要为
List<T>
的相关成员编写转发方法。五十多次。你显然不怕冗长,我们在这里讨论的是非常少量的代码;这是几分钟的工作。更新
我考虑了更多,还有另一个原因是不将足球队建模为球员列表。事实上,将足球队建模为也有球员名单可能是一个坏主意。拥有球员名单的球队的问题在于,你得到的是球队在某一时刻的快照。我不知道你对这个类(class)的商业案例是什么,但如果我有一个代表一支足球队的类(class),我会问它一些问题,比如“2003 年到 2013 年有多少海鹰队球员因伤缺席比赛?”或者“之前为另一支球队效力的丹佛球员中,哪位球员的跑码同比增幅最大?”或“Did the Piggers go all the way this year?”
也就是说,在我看来,一支足球队被很好地建模为历史事实的集合,例如球员何时被招募、受伤、退役等。显然,当前的球员名单是一个重要的事实,应该是最重要的——中心,但您可能还想对这个对象做其他有趣的事情,这些事情需要更多的历史视角。
关于c# - 为什么不从 List<T> 继承?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51722074/