为什么不从 List 继承<T> ? - Why not inherit from List<T>?

问题:

When planning out my programs, I often start with a chain of thought like so:在规划我的程序时,我经常以这样的思路开始:

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.此列表的顺序表示球员在名册中列出的顺序。

But I realize later that teams also have other properties, besides the mere list of players, that must be recorded.但后来我意识到,除了球员名单之外,球队还有其他一些必须记录的属性。 For example, the running total of scores this season, the current budget, the uniform colors, a string representing the name of the team, etc..例如,本赛季的总得分、当前预算、球衣颜色、代表球队名称的string等。

So then I think:那么我想:

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 (an int ).好吧,一个足球队就像一个球员列表,但另外,它有一个名字(一个string )和一个总得分(一个int )。 .NET does not provide a class for storing football teams, so I will make my own class. .NET 不提供用于存储足球队的类,因此我将创建自己的类。 The most similar and relevant existing structure is List<FootballPlayer> , so I will inherit from it:最相似和最相关的现有结构是List<FootballPlayer> ,所以我将从它继承:

class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }

But it turns out that a guideline says you shouldn't inherit from List<T> .但事实证明,一条指导方针说你不应该从List<T>继承 I'm thoroughly confused by this guideline in two respects.我对这个指南在两个方面感到非常困惑。

Why not?为什么不?

Apparently List is somehow optimized for performance .显然List以某种方式针对性能进行了优化 How so?为何如此? What performance problems will I cause if I extend List ?如果我扩展List会导致什么性能问题? What exactly will break?究竟会破什么?

Another reason I've seen is that List is provided by Microsoft, and I have no control over it, so I cannot change it later, after exposing a "public API" .我看到的另一个原因是List是由 Microsoft 提供的,我无法控制它,因此在公开“公共 API”后,我无法稍后更改它 But I struggle to understand this.但我很难理解这一点。 What is a public API and why should I care?什么是公共 API,我为什么要关心? If my current project does not and is not likely to ever have this public API, can I safely ignore this guideline?如果我当前的项目没有也不太可能有这个公共 API,我可以安全地忽略这个指南吗? If I do inherit from List and it turns out I need a public API, what difficulties will I have?如果我确实从List继承并且结果证明我需要一个公共 API,我会遇到什么困难?

Why does it even matter?为什么这很重要? A list is a list.列表是一个列表。 What could possibly change?什么可能改变? What could I possibly want to change?我可能想要改变什么?

And lastly, if Microsoft did not want me to inherit from List , why didn't they make the class sealed ?最后,如果微软不想让我从List继承,他们为什么不让这个类sealed

What else am I supposed to use?我还应该使用什么?

Apparently, for custom collections, Microsoft has provided a Collection class which should be extended instead of List .显然,对于自定义集合,微软提供了一个Collection类,它应该被扩展而不是List But this class is very bare, and does not have many useful things, such as AddRange , for instance.但是这个类非常简单,没有很多有用的东西, 例如AddRange jvitor83's answer provides a performance rationale for that particular method, but how is a slow AddRange not better than no AddRange ? jvitor83 的回答为该特定方法提供了性能原理,但是慢的AddRange怎么比没有AddRange

Inheriting from Collection is way more work than inheriting from List , and I see no benefit.Collection继承比从List继承要多得多,我看不出有什么好处。 Surely Microsoft wouldn't tell me to do extra work for no reason, so I can't help feeling like I am somehow misunderstanding something, and inheriting Collection is actually not the right solution for my problem.微软肯定不会无缘无故地告诉我做额外的工作,所以我不禁觉得我在某种程度上误解了一些东西,而继承Collection实际上并不是我的问题的正确解决方案。

I've seen suggestions such as implementing IList .我已经看到了诸如实施IList建议。 Just no.就是不行。 This is dozens of lines of boilerplate code which gains me nothing.这是几十行样板代码,对我没有任何帮助。

Lastly, some suggest wrapping the List in something:最后,有些人建议将List包装在一些东西中:

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

There are two problems with this:这有两个问题:

  1. It makes my code needlessly verbose.它使我的代码不必要地冗长。 I must now call my_team.Players.Count instead of just my_team.Count .我现在必须调用my_team.Players.Count而不仅仅是my_team.Count Thankfully, with C# I can define indexers to make indexing transparent, and forward all the methods of the internal List ... But that's a lot of code!值得庆幸的是,使用 C# 我可以定义索引器以使索引透明,并转发内部List所有方法......但这是很多代码! What do I get for all that work?所有这些工作我能得到什么?

  2. It just plain doesn't make any sense.简单的说没有任何意义。 A football team doesn't "have" a list of players.足球队没有“拥有”球员名单。 It is the list of players.球员名单。 You don't say "John McFootballer has joined SomeTeam's players".你不会说“John McFootballer 加入了 SomeTeam 的球员”。 You say "John has joined SomeTeam".您说“John 已加入 SomeTeam”。 You don't add a letter to "a string's characters", you add a letter to a string.您不会向“字符串的字符”添加字母,而是向字符串添加字母。 You don't add a book to a library's books, you add a book to a library.您不是将一本书添加到图书馆的书籍中,而是将一本书添加到图书馆。

I realize that what happens "under the hood" can be said to be "adding X to Y's internal list", but this seems like a very counter-intuitive way of thinking about the world.我意识到“幕后”发生的事情可以说是“将 X 添加到 Y 的内部列表”,但这似乎是一种非常反直觉的思考世界的方式。

My question (summarized)我的问题(总结)

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?表示数据结构的正确 C# 方式是什么,“逻辑上”(也就是说,“对人类思维”)只是带有一些花里胡哨的things list

Is inheriting from List<T> always unacceptable?List<T>继承总是不可接受的吗? When is it acceptable?什么时候可以接受? Why/why not?为什么/为什么不? What must a programmer consider, when deciding whether to inherit from List<T> or not?程序员在决定是否从List<T>继承时必须考虑什么?


解决方案:

参考一: https://stackoom.com/question/1T185
参考二: Why not inherit from List?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章