为什么不从 List<T> 继承? [英] Why not inherit from List&lt;T&gt;?

查看:29
本文介绍了为什么不从 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.

但后来我意识到球队还有其他属性,除了球员名单之外,必须记录下来.例如,本赛季的总得分、当前预算、球衣颜色、代表球队名称的string等.

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)和一个总得分(一个int)..NET 不提供用于存储足球队的类,因此我将创建自己的类.最相似和相关的现有结构是List,所以我将继承它:

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). .NET does not provide a class for storing football teams, so I will make my own class. The most similar and relevant existing structure is List<FootballPlayer>, so I will inherit from it:

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

但事实证明,指导方针说你不应该从 List 继承一>.我对这个指南在两个方面感到非常困惑.

But it turns out that a guideline says you shouldn't inherit from List<T>. I'm thoroughly confused by this guideline in two respects.

显然List 以某种方式针对性能进行了优化.为何如此?如果我扩展 List 会导致什么性能问题?究竟会破坏什么?

Apparently List is somehow optimized for performance. How so? What performance problems will I cause if I extend List? What exactly will break?

我看到的另一个原因是 List 是微软提供的,我无法控制它,所以 我无法在暴露公共 API"后更改它.但我很难理解这一点.什么是公共 API,我为什么要关心?如果我当前的项目没有也不太可能有这个公共 API,我可以安全地忽略这个指南吗?如果我确实继承了 List 并且 事实证明我需要一个公共 API,我会遇到什么困难?

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". But I struggle to understand this. What is a public API and why should I care? If my current project does not and is not likely to ever have this public API, can I safely ignore this guideline? If I do inherit from List and it turns out I need a public API, what difficulties will I have?

为什么这很重要?列表是一个列表.什么可能改变?我可能想要改变什么?

Why does it even matter? A list is a list. What could possibly change? What could I possibly want to change?

最后,如果微软不想让我继承List,他们为什么不让类密封?

And lastly, if Microsoft did not want me to inherit from List, why didn't they make the class sealed?

显然,对于自定义集合,微软提供了一个 Collection 类,它应该被扩展而不是 List.但是这个类很裸,没有很多有用的东西,比如AddRange,例如.jvitor83 的答案 提供了该特定方法的性能原理,但是缓慢的 AddRange 如何不是更好比没有AddRange?

Apparently, for custom collections, Microsoft has provided a Collection class which should be extended instead of List. But this class is very bare, and does not have many useful things, such as AddRange, for instance. jvitor83's answer provides a performance rationale for that particular method, but how is a slow AddRange not better than no AddRange?

Collection 继承比从 List 继承要多得多,我看不出有什么好处.微软肯定不会无缘无故地告诉我做额外的工作,所以我不禁觉得我在某种程度上误解了一些东西,而继承 Collection 实际上并不是我的问题的正确解决方案.

Inheriting from Collection is way more work than inheriting from List, and I see no benefit. 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.

我已经看到了诸如实施 IList 之类的建议.就是不行.这是几十行样板代码,我一无所获.

I've seen suggestions such as implementing IList. Just no. This is dozens of lines of boilerplate code which gains me nothing.

最后,有些人建议将 List 包装在一些东西中:

Lastly, some suggest wrapping the List in something:

class FootballTeam 
{ 
    public List<FootballPlayer> Players; 
}

这有两个问题:

  1. 它使我的代码变得不必要地冗长.我现在必须调用 my_team.Players.Count 而不是 my_team.Count.值得庆幸的是,使用 C# 我可以定义索引器使索引透明,并转发内部 List 的所有方法......但那是很多代码!所有这些工作我能得到什么?

  1. It makes my code needlessly verbose. I must now call my_team.Players.Count instead of just 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! What do I get for all that work?

这只是简单的没有任何意义.足球队没有拥有"球员名单.它球员名单.你不会说John McFootballer 加入了 SomeTeam 的球员".您说John 已加入 SomeTeam".您不会向字符串的字符"添加字母,而是向字符串添加字母.您不是将一本书添加到图书馆的图书中,而是将一本书添加到图书馆中.

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". You say "John has joined 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.

我意识到幕后"发生的事情可以说是将 X 添加到 Y 的内部列表中",但这似乎是一种非常反直觉的思考世界的方式.

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.

表示数据结构的正确 C# 方式是什么,逻辑上"(也就是说,对人的头脑")只是 things<的 list/code> 有一些花里胡哨?

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?

List 继承总是不可接受的吗?什么时候可以接受?为什么/为什么不?程序员在决定是否从 List 继承时必须考虑什么?

Is inheriting from List<T> always unacceptable? When is it acceptable? Why/why not? What must a programmer consider, when deciding whether to inherit from List<T> or not?

推荐答案

这里有一些很好的答案.我想补充以下几点.

There are some good answers here. I would add to them the following points.

表示数据结构的正确 C# 方式是什么,逻辑上"(也就是说,对人类的思维")只是带有一些花里胡哨的事物列表?

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?

请任何十名熟悉足球存在的非计算机程序员填写空白:

Ask any ten non-computer-programmer people who are familiar with the existence of football to fill in the blank:

足球队是一种特殊的_____

A football team is a particular kind of _____

有没有任何人说有一些花里胡哨的足球运动员名单",或者他们都说运动队"或俱乐部"或组织"?你认为一支足球队是一种特殊类型的球员,这是你人类的思想,而且只有你的人类思想.

Did anyone say "list of football players with a few bells and whistles", or did they all say "sports team" or "club" or "organization"? Your notion that a football team is a particular kind of list of players is in your human mind and your human mind alone.

List 是一种机制.足球队是一个业务对象——也就是说,一个对象代表了程序的业务领域中的一些概念.不要混合这些!一支足球队是一种团队;它有一个名册,名册是一个球员名单.名单不是特定类型的球员名单.名册球员名单.所以创建一个名为 Roster 的属性,它是一个 List.并在您使用它时使其ReadOnlyList,除非您相信每个了解足球队的人都可以从名单中删除球员.

List<T> is a mechanism. Football team is a business object -- that is, an object that represents some concept that is in the business domain of the program. Don't mix those! A football team is a kind of team; it has a roster, a roster is a list of players. A roster is not a particular kind of list of players. A roster is a list of players. So make a property called Roster that is a List<Player>. And make it ReadOnlyList<Player> while you're at it, unless you believe that everyone who knows about a football team gets to delete players from the roster.

List 继承总是不可接受的吗?

Is inheriting from List<T> always unacceptable?

谁不能接受?我?号

什么时候可以接受?

当您正在构建一种扩展List机制的机制时.

When you're building a mechanism that extends the List<T> mechanism.

程序员在决定是否从 List 继承时必须考虑什么?

What must a programmer consider, when deciding whether to inherit from List<T> or not?

我是在构建机制还是业务对象?

但那是很多代码!所有这些工作我能得到什么?

But that's a lot of code! What do I get for all that work?

您花了更多时间输入您的问题,而您需要为 List 的相关成员编写转发方法五十次.您显然不怕冗长,而且我们在这里讨论的是非常少量的代码;这是几分钟的工作.

You spent more time typing up your question that it would have taken you to write forwarding methods for the relevant members of List<T> fifty times over. You're clearly not afraid of verbosity, and we are talking about a very small amount of code here; this is a few minutes work.

我考虑了更多,还有另一个原因是不将足球队建模为球员列表.事实上,将一支足球队建模为一个球员列表可能是个坏主意.拥有球员名单的球队的问题在于,你得到的是球队的快照在某个时刻.我不知道你对这个班级的商业案例是什么,但如果我有一个代表一支足球队的班级,我会问它这样的问题,比如2003 年到 2013 年有多少海鹰队球员因伤缺席比赛?"或者之前为另一支球队效力的丹佛球员中,哪位球员的跑码同比增幅最大?"或猪猪队今年一路走来了吗?"

I gave it some more thought and there is another reason to not model a football team as a list of players. In fact it might be a bad idea to model a football team as having a list of players too. The problem with a team as/having a list of players is that what you've got is a snapshot of the team at a moment in time. I don't know what your business case is for this class, but if I had a class that represented a football team I would want to ask it questions like "how many Seahawks players missed games due to injury between 2003 and 2013?" or "What Denver player who previously played for another team had the largest year-over-year increase in yards ran?" or "Did the Piggers go all the way this year?"

也就是说,在我看来,一支足球队被很好地建模为历史事实的集合,例如球员何时被招募、受伤、退役等.显然,当前的球员名单是重要的事实可能应该是最重要的,但您可能想用这个对象做其他有趣的事情,需要更多的历史视角.

That is, a football team seems to me to be well modeled as a collection of historical facts such as when a player was recruited, injured, retired, etc. Obviously the current player roster is an important fact that should probably be front-and-center, but there may be other interesting things you want to do with this object that require a more historical perspective.

这篇关于为什么不从 List<T> 继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆