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
等。 app
So then I think: 因此我想: less
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 (anint
). 好的,一支足球隊就像一個球員名單,可是另外,它還有一個名字(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 isList<FootballPlayer>
, so I will inherit from it: 最類似和相關的現有結構是List<FootballPlayer>
,因此我將從它繼承: ideclass 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. 我對該指南在兩個方面徹底感到困惑。 性能
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提供,而且我沒法控制它,所以之後在公開「 public 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,我會遇到什麼困難? ui
Why does it even matter? 爲何如此重要? A list is a list. 列表就是列表。 What could possibly change? 有什麼可能改變? What could I possibly want to change? 我可能要更改什麼? this
And lastly, if Microsoft did not want me to inherit from List
, why didn't they make the class sealed
? 最後,若是Microsoft不但願我從List
繼承,他們爲何不將類sealed
?
Apparently, for custom collections, Microsoft has provided a Collection
class which should be extended instead of List
. 顯然,對於自定義集合,Microsoft提供了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. 固然,Microsoft不會平白無故地告訴我作額外的工做,所以我不由感到本身在某種程度上誤解了某些東西,而繼承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: 這有兩個問題:
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? 我能從全部工做中獲得什麼?
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". 您說「約翰加入了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的內部列表中」,但這彷佛是一種很是反常的思考世界的方式。
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>
繼承時必須考慮什麼?