爲什麼不從 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?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章