在计划程序时,我通常会像这样思考:
足球队只是足球运动员的名单。因此,我应该用: var football_team = new List<FootballPlayer>(); 该列表的顺序代表了在名单中列出球员的顺序。
足球队只是足球运动员的名单。因此,我应该用:
var football_team = new List<FootballPlayer>();
该列表的顺序代表了在名单中列出球员的顺序。
但是后来我意识到,除了球员名单外,球队还有其他属性,必须加以记录。例如,本赛季的总得分,当前预算,统一的颜色,string代表球队名称的a 等。
string
所以我想:
好的,一支足球队就像一个球员名单,但此外,它还有一个名字(a string)和一个总得分(an int)。.NET没有提供用于存储足球队的课程,因此我将创建自己的课程。最相似,最相关的现有结构是List<FootballPlayer>,因此我将从中继承: class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
好的,一支足球队就像一个球员名单,但此外,它还有一个名字(a string)和一个总得分(an int)。.NET没有提供用于存储足球队的课程,因此我将创建自己的课程。最相似,最相关的现有结构是List<FootballPlayer>,因此我将从中继承:
int
List<FootballPlayer>
class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
但事实证明,指南指出您不应继承List<T>。我对该指南在两个方面完全感到困惑。
List<T>
显然List在某种程度上针对性能进行了优化。为何如此?如果我扩展,会导致什么性能问题List?到底会破裂什么?
List
我看到的另一个原因List是Microsoft提供的,并且我无法控制它,因此在公开“公共API”之后,以后不能更改它。但是我很难理解这一点。什么是公共API,我为什么要关心?如果我当前的项目没有并且不太可能拥有此公共API,那么我可以安全地忽略此指南吗?如果我确实继承自我,List 而 事实证明我需要一个公共API,我会遇到什么困难?
为什么如此重要?列表就是列表。有什么可能改变?我可能要更改什么?
最后,如果微软不希望我继承List,他们为什么不上课sealed?
sealed
显然,对于自定义集合,Microsoft提供了一个Collection应该扩展而不是的类List。但这个类是非常裸露,并没有多少有用的东西,比如AddRange,例如。jvitor83的答案提供了该特定方法的性能原理,但是慢AddRange不是没有总比没有更好AddRange?
Collection
AddRange
从Collection继承比从继承进行的工作量更大List,我看不出任何好处。当然,Microsoft不会无故告诉我不要做额外的工作,所以我不禁会觉得自己在某种程度上误解了某些东西,而继承Collection实际上并不是解决我的问题的正确方法。
我已经看到了诸如实施的建议IList。就是不行。这是几十行样板代码,对我毫无帮助。
IList
最后,有些人建议将包裹起来List:
class FootballTeam { public List<FootballPlayer> Players; }
这有两个问题:
它使我的代码不必要地冗长。我现在必须打电话,my_team.Players.Count而不仅仅是my_team.Count。幸运的是,使用C#,我可以定义索引器以使索引透明化,并转发内部的所有方法List…但是,这很多代码!我能从所有工作中得到什么?
my_team.Players.Count
my_team.Count
只是没有任何意义。一支足球队没有“拥有”球员名单。这 是 球员名单。您不会说“ John McFootballer已加入SomeTeam的球员”。您说“约翰加入了SomeTeam”。您没有在“字符串的字符”中添加字母,而是在字符串中添加了字母。您没有将书添加到图书馆的书中,而是将书添加到图书馆。
我意识到,“幕后”发生的事情可以说是“将X添加到Y的内部列表中”,但这似乎是一种非常反常的思考世界的方式。
什么是代表一个数据结构,其中,“逻辑”(即,“以人的心灵”)仅仅是一个正确的C#这样list的things与一些花俏?
list
things
从List<T>永远继承是不可接受的吗?什么时候可以接受?为什么/为什么不呢?程序员在决定是否继承时必须考虑什么List<T>?
这里有一些很好的答案。我将向他们补充以下几点。
什么是表示数据结构的正确C#方法,“逻辑上”(也就是说,“对人类而言”)只是一个带有一些花哨的东西的列表?
让任何十位熟悉足球存在的非计算机编程人员来填补空白:
足球队是_____的一种特殊类型
难道 有人 说“有一些花俏的足球运动员名单”,还是他们都说“运动队”或“俱乐部”或“组织”?您认为足球队是 一种特殊的球员名单, 这在您的人心中和您的人心中都是存在的。
List<T>是一种 机制 。足球队是一个 业务对象 ,即代表该程序 业务领域 中某些概念的对象。不要混那些!足球队 是一种 球队。它 有一个 名册,一个名册 是一个球员名单 。名册不是 特定的球员名单 。名册 是 球员名单。因此,让一个名为属性Roster这是一个List<Player>。并使其ReadOnlyList<Player>当你在它,除非你相信大家谁知道一个足球队获得从名册上删除的球员。
Roster
List<Player>
ReadOnlyList<Player>
从List<T>永远继承是不可接受的吗?
谁不能接受?我?没有。
什么时候可以接受?
在构建 扩展该List<T>机制的机制时。
程序员在决定是否继承时必须考虑什么List<T>?
我是在建立 机制 还是 业务对象 ?
但这是很多代码!我能从所有工作中得到什么?
您花了更多时间输入问题,以至于需要为相关成员编写转发方法List<T>50次以上。您显然不怕冗长,在这里我们谈论的代码很少。这是几分钟的工作。
我再三考虑一下,还有另一个原因不将足球队建模为球员名单。实际上,将足球队建模为也 有 球员名单可能不是一个好主意。与团队/有球员名单的问题是,你所得到的是一个 快照 的球队 在某个时刻 。我不知道您在这堂课上的业务案例是什么,但是如果我有一堂代表足球队的课,我想问一下这样的问题:“有多少海鹰球员因2003年至2013年受伤而缺席比赛?” 还是“以前为另一支球队效力的丹佛球员在码数上的同比增长最大?” 或“ 今年猪头人一路走? ”
就是说,在我看来,一支足球队的模型被很好地模拟为 历史事实的集合, 例如球员被招募,受伤,退休等 的历史事实 。显然,目前的球员名册是一个重要的事实,应该很重要。居中,但您可能还需要对这个对象进行其他有趣的操作,这些操作需要更多的历史视角。