在计划我的程序时,我经常从这样的思路开始:
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.
但后来我意识到,除了球员名单之外,球队还有其他必须记录的属性。例如,本赛季的总得分、当前预算、 Jersey 颜色、string。代表队名等。
然后我想:
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). .NET does not provide a class for storing football teams, so I will make my own class. The most similar and relevant existing structure isList<FootballPlayer>, so I will inherit from it:class FootballTeam : List<FootballPlayer> { public string TeamName; public int RunningTotal }
但事实证明a guideline says you shouldn't inherit from List<T> .我在两个方面对这条准则感到非常困惑。
显然 List is somehow optimized for performance .怎么会这样?如果我扩展 List 会导致什么性能问题? ?究竟什么会破坏?
我看到的另一个原因是 List由 Microsoft 提供,我无法控制它,所以 I cannot change it later, after exposing a "public API" .但我很难理解这一点。什么是公共(public) API,我为什么要关心?如果我当前的项目没有也不太可能有这个公共(public) API,我可以放心地忽略这个指南吗?如果我继承自 List 并且事实证明我需要一个公共(public)API,我会有什么困难?
为什么这很重要?列表就是列表。什么可能会改变?我可能想要改变什么?
最后,如果 Microsoft 不想让我继承 List ,他们为什么不上课 sealed ?
显然,对于自定义集合,微软提供了一个Collection应该扩展而不是 List 的类.但是这个类很简单,没有多少有用的东西,such as AddRange , 例如。 jvitor83's answer提供了该特定方法的性能原理,但是缓慢的 AddRange 是如何实现的?不比没有好 AddRange ?
继承自 Collection比从 List 继承更多的工作,我看不出有什么好处。微软肯定不会让我无缘无故地做额外的工作,所以我不禁觉得我不知何故误解了一些东西,并继承了Collection实际上不是我的问题的正确解决方案。
我看过一些建议,例如实现 IList .就是不行。这是几十行样板代码,我一无所获。
最后,有人建议包装 List在某事中:
class FootballTeam
{
public List<FootballPlayer> Players;
}
这有两个问题:
它使我的代码不必要地冗长。我现在必须调用 my_team.Players.Count而不仅仅是 my_team.Count .值得庆幸的是,使用 C# 我可以定义索引器以使索引透明,并转发内部 List 的所有方法。 ...但是那是很多代码!我做这些工作能得到什么?
简单明了没有任何意义。足球队没有球员名单。它是玩家列表。您不会说“John McFootballer 加入了 SomeTeam 的球员”。你说“约翰加入了 SomeTeam”。您不向“字符串的字符”添加字母,而是向字符串添加字母。您不是将一本书添加到图书馆的图书中,而是将一本书添加到图书馆中。
我意识到“幕后”发生的事情可以说是“将 X 添加到 Y 的内部列表”,但这似乎是一种非常违反直觉的思考世界的方式。
表示数据结构的正确 C# 方法是什么,“逻辑上”(也就是说,“对人的思维”而言)只是一个 list的 things有一些花里胡哨的东西?
继承自List<T>总是不能接受?什么时候可以接受?为什么/为什么不?在决定是否从 List<T> 继承时,程序员必须考虑什么还是不是?
最佳答案
这里有一些很好的答案。我会向他们添加以下几点。
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?
请任意十个熟悉足球存在的非计算机程序员填空:
A football team is a particular kind of _____
有人说“带有一些花里胡哨的足球运动员名单”,还是他们都说“运动队”或“俱乐部”或“组织”?你认为足球队是一种特殊类型的球员的想法存在于你的人类思维中,而且只存在于你的人类思维中。
List<T>是一种机制。足球队是一个业务对象 —— 即表示程序业务领域 中的某些概念的对象。不要混合那些!一支足球队是一种球队;它有一个花名册,一个花名册是一个玩家列表。花名册不是特定类型的球员名单。花名册是玩家列表。所以创建一个名为 Roster 的属性那是一个List<Player> .并让它成为ReadOnlyList<Player>除非您相信每个了解足球队的人都可以从花名册中删除球员。
Is inheriting from
List<T>always unacceptable?
谁不接受?我?没有。
When is it acceptable?
当您构建扩展 List<T> 的机制时机制。
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<T> 的相关成员编写转发方法要花更多时间五十次以上。你显然不怕冗长,我们在这里讨论的代码量非常小;这是几分钟的工作。
我仔细考虑了一下,还有另一个原因不将足球队建模为球员列表。事实上,将足球队建模为也有球员名单可能不是一个好主意。拥有球员名单的球队的问题在于,您得到的是球队某个时刻的快照。我不知道你的这个类(class)的商业案例是什么,但如果我有一个代表足球队的类(class),我想问它这样的问题:“2003 年到 2013 年间有多少海鹰队球员因伤缺席比赛?”或者“之前为另一支球队效力的丹佛球员的跑码数同比增幅最大?”或“Did the Piggers go all the way this year?”
也就是说,在我看来,足球队可以很好地建模为历史事实的集合,例如球员何时被招募、受伤、退役等。显然,当前球员名单是重要的事实可能应该放在前面和中心,但您可能还想用这个对象做其他有趣的事情,需要更多的历史视角。
关于c# - 为什么不继承List<T>呢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21692193/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我正在学习如何在我的Ruby代码中使用Module.prepend而不是alias_method_chain,我注意到有些人使用send调用它(example):ActionView::TemplateRenderer.send(:prepend,ActionViewTemplateRendererWithCurrentTemplate)而其他人直接调用它(example):ActionView::TemplateRenderer.prepend(ActionViewTemplateRendererWithCurrentTemplate)而且,虽然我还没有看到任何人使用这种风格,但我从
我在用Ruby执行简单任务时遇到了一件奇怪的事情。我只想用每个方法迭代字母表,但迭代在执行中先进行:alfawit=("a".."z")puts"That'sanalphabet:\n\n#{alfawit.each{|litera|putslitera}}"这段代码的结果是:(缩写)abc⋮xyzThat'sanalphabet:a..z知道为什么它会这样工作或者我做错了什么吗?提前致谢。 最佳答案 因为您的each调用被插入到在固定字符串之前执行的字符串文字中。此外,each返回一个Enumerable,实际上您甚至打印它。试试
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll