当我计划我的计划时,我通常会从一系列的 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; 
}

这有两个问题:

  1. 这让我的代码变得毫无必要的冗长.我现在必须拨打my_team.Players.Count而不是my_team.Count.谢天谢地,有了C#我可以定义索引器以使索引透明,并转发内部List的所有方法...但这是很多代码!这些工作我能得到什么?

  2. 这是毫无意义的.足球队没有球员名单.这是球员名单上的is人.你不会说"约翰·麦克斯波尔加入了某个球队的球员".你说"约翰加入了某个团队".你不会在"字符串的字符"中添加字母,而是在字符串中添加字母.你不是在图书馆的书中添加一本书,而是在图书馆中添加一本书.

我意识到"引擎盖下"发生的事情可以说是"把X加到Y的内部 list 上",但这似乎是一种非常违反直觉的看待世界的方式.

我的问题(摘要)

什么是表示数据 struct 的正确C#方式,数据 struct 在"逻辑上"(也就是说,"给人的头脑")只是thingslist,只有几个花哨?

List<T>岁开始继承总是不可接受的吗?什么时候可以接受?为什么?当程序员决定是否从List<T>继承时,程序员必须考虑什么?

推荐答案

这里有一些很好的答案.我想补充以下几点.

表示数据 struct 的正确C#方式是什么?"逻辑上"(也就是说,"对人类思维而言")数据 struct 只是一些花哨的东西的列表.

请任何十位熟悉足球存在的非计算机程序员填写以下空白:

足球队是一种特殊的运动_____

anyone人说的是"带着一些铃铛和口哨的足球运动员名单",还是他们都说的是"运动队"、"俱乐部"或"组织"?你认为足球队是a particular kind of list of players人的 idea 存在于你的人类思维中,而且仅存在于你的人类思维中.

List<T>mechanism.足球队是一个business object,也就是说,一个代表程序business domain中某个概念的对象.别把它们混在一起!足球队;它有has a个花名册,is a list of players个花名册.花名册不是particular kind of list of players.名册上有球员名单.因此,创建一个名为Roster的属性,即List<Player>.如果你不相信每一个了解足球队的人都可以把球员从名单上删除,那就把它设为ReadOnlyList<Player>.

List<T>开始继承总是不能接受的吗?

谁不能接受?我不

什么时候可以接受?

当你在建造一种机制时,extends the 100 mechanism.

当程序员决定是否从List<T>继承时,程序员必须考虑什么?

我是在建mechanism还是business object

但这是很多代码!这些工作我能得到什么?

你花了更多的时间输入你的问题,这将需要你写转发方法的相关成员List<T> 50倍以上.很明显,您并不害怕冗长,我们在这里讨论的是非常少量的代码;这是几分钟的工作.

使现代化

我仔细考虑了一下,还有另一个理由不把一支足球队作为球员名单的模型.事实上,把一支足球队也模拟成一份球员名单可能是个坏主意.有球员名单的球队的问题是,你得到的是at a moment in time队的snapshot名球员.我不知道你们在这门课上的商业 case 是什么,但如果我有一门代表足球队的课,我想问它一些问题,比如"在2003年到2013年间,有多少海鹰队的球员因为受伤而错过了比赛?"或者"哪位曾为另一支球队效力的丹佛球员的跑位同比增长最大?"或者"Did the Piggers go all the way this year?"

也就是说,在我看来,一支足球队似乎被很好地模拟为a collection of historical facts人,比如一名球员被招募、受伤、退役等.显然,当前的球员名单是一个重要的事实,可能应该是最前沿和最中锋,但你可能想用这个对象做其他有趣的事情,需要更具历史意义的视角.

.net相关问答推荐

[x.x.x,)在Packages.lock.json依赖项中是什么意思?

如何将 signalR 添加到不同项目中的后台服务?

更改列表中的值

为什么(真的吗?)List 实现所有这些接口,而不仅仅是 IList

如何判断属性设置器是否公开

AsyncLocal 的语义与逻辑调用上下文有何不同?

单击关闭按钮时隐藏表单而不是关闭

maxRequestLength 的最大值?

如何在 C# 4.0 中使任务进入睡眠状态(或延迟)?

在 C# 中转义命令行参数

如何结合 ||条件语句中的运算符

NuGetPackageImportStamp 有什么用?

创建多个线程并等待所有线程完成

变量MyException已声明但从未使用

单元测试 C# 保护方法

ConcurrentDictionary TryRemove 何时返回 false

在 Windows 窗体 C# 应用程序中拥有配置文件的最简单方法

WPF 中的 Application.DoEvents() 在哪里?

从不同程序集中的类名中解析类型

连接字符串而不是使用一堆 TextBlocks