当我计划我的计划时,我通常会从一系列的 idea 开始,如下所示:
一支足球队就是一份足球运动员的名单.因此,我应该用以下几点来代表它:
var football_team = new List<FootballPlayer>();
这份名单的顺序代表了球员在名册上的排列顺序.
但后来我意识到,除了球员名单之外,球队还有其他必须记录的属性.例如,本赛季的总得分、当前预算、制服 colored颜色 、代表球队名称的string
,等等.
所以我想:
好的,一支足球队就像一份球员名单,但除此之外,它还有一个名字(
string
)和一个连续的总比分(int
)..NET不提供用于存储足球队的类,所以我将创建我自己的类.最相似和相关的现有 struct 是List<FootballPlayer>
,因此我将继承它: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".但我很难理解这一点.什么是公共API,我为什么要关心?如果我当前的项目没有也不太可能有这个公共API,我可以安全地忽略这个指导方针吗?如果我真的继承了List
and,原来我需要一个公共API,我会有什么困难呢?
为什么这很重要? list 就是 list .什么可能会改变?我可能想要改变什么?
最后,如果微软不想让我继承List
,为什么他们不把类设为sealed
呢?
我还应该用什么呢?
显然,对于定制集合,微软提供了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
的所有方法...但这是很多代码!这些工作我能得到什么?这是毫无意义的.足球队没有球员名单.这是球员名单上的is人.你不会说"约翰·麦克斯波尔加入了某个球队的球员".你说"约翰加入了某个团队".你不会在"字符串的字符"中添加字母,而是在字符串中添加字母.你不是在图书馆的书中添加一本书,而是在图书馆中添加一本书.
我意识到"引擎盖下"发生的事情可以说是"把X加到Y的内部 list 上",但这似乎是一种非常违反直觉的看待世界的方式.
我的问题(摘要)
什么是表示数据 struct 的正确C#方式,数据 struct 在"逻辑上"(也就是说,"给人的头脑")只是things
的list
,只有几个花哨?
从List<T>
岁开始继承总是不可接受的吗?什么时候可以接受?为什么?当程序员决定是否从List<T>
继承时,程序员必须考虑什么?