当我计划我的计划时,我通常会从一系列的 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相关问答推荐

如何处理以用户为中心的CSP现时值?(uc-lock.bundle.js)

使用PowerShell在Windows容器内安装exe

在 .NET 7 项目上设置 Sentry 时遇到问题

使用 PowerShell 从文件夹中获取文件名的最快\最好的方法是什么?

如何获得友好的操作系统版本名称?

代理、包装器或外观类之间有什么区别

Environment.TickCount 与 DateTime.Now

我什么时候应该在 C# 中使用使用块?

.NET 等价于旧的 vb left(string, length) 函数

无法加载文件或程序集'System.ComponentModel.Annotations,版本 = 4.1.0.0

WCF服务客户端:内容类型text/html;响应消息的charset=utf-8 与绑定的内容类型不匹配

为什么有些对象属性是 UnaryExpression 而有些是 MemberExpression?

您可以使用 Xamarin 开发 Linux 应用程序吗?

如何使用 DateTime 指定一天中的最晚时间

C# 应用程序中的全局键盘捕获

obj 文件夹是为了什么而生成的?

程序员应该使用 SSIS,如果是,为什么?

多个列表与 IEnumerable.Intersect() 的交集

为什么 IList 不支持 AddRange

嵌套捕获组如何在正则表达式中编号?