【问题标题】:Method overloads resolution and Jon Skeet's Brain Teasers方法重载决议和 Jon Skeet 的脑筋急转弯
【发布时间】:2011-02-14 05:31:41
【问题描述】:

Jon's Brain Teasers

这里有剧透...

我正在查看answer 到#1,我必须承认我从来不知道在重载解决方案中会出现这种情况。但是为什么是这样的。在我的小脑袋里,Derived.Foo(int) 似乎是顺理成章的路线。

这个设计决策背后的逻辑是什么?

奖励时间!

此行为是 C# 规范、CLR 实现还是编译器的结果?

【问题讨论】:

  • 这绝对是一种奇怪的行为!他们可能是在周五下午午餐时间喝了太多啤酒后设计的。
  • 或者经过数小时的思考后,最佳的整体行为会是什么;)
  • 我猜你看到的和我一样,因为我们一直在讨论完全相同的问题的答案!
  • 现在这算作你的标签还是我的标签? :)
  • 需要在另一个帖子中发布另一个链接...Versioning, Virtual, and Override

标签: c# operator-overloading


【解决方案1】:

这种行为是经过深思熟虑和精心设计的。原因是因为这种选择减轻了一种形式的脆性基类故障的影响。

阅读我关于该主题的文章了解更多详情。

http://blogs.msdn.com/ericlippert/archive/2007/09/04/future-breaking-changes-part-three.aspx

【讨论】:

  • 我知道在某个地方会有充分的理由!那么(对于 Bonus Time!)这是 C# 还是 CLR 的规范?
  • @runrunraygun:CLR 没有重载解析算法;重载决议是一个语言概念。 CLR IL 仅具有调用特定位置中的任何方法引用的指令。所以这不可能是一个 CLR 规范。此行为在 C# 规范第 7.6.5.1 节中指定,开始于“候选方法集被缩减为仅包含来自最派生类型的方法......”
【解决方案2】:

这是一个可能的解释:

当编译器链接方法调用时,它首先在继承链中最低的类中查找(在本例中为Derived 类)。它的实例方法被检查和匹配。重写的方法Foo不是Derived的实例方法,而是Base类的实例方法。

原因可能是性能,正如 Jack30lena 所建议的那样,但也可能是编译器如何解释编码器的意图。开发人员的预期代码行为存在于继承链底部的代码中,这是一个安全的假设。

【讨论】:

  • “最低”是指离基类最远的东西?通常我会将离事物底部最远的事物描述为“最高”事物。 (再说一遍,树的根是树中最高的节点,这也没有意义……)也就是说,您的分析是正确的;派生类的开发者比基类的开发者知道的更多,所以他们的方法优先。
  • 我从树的角度思考。真正有趣的是为什么这种隐藏方式至少不会导致警告。本质上,任何具有更通用参数的实例方法都会有效地隐藏更具体的覆盖。我知道这段代码并非完全无法访问(根据 Foxfire),但它仍然是隐藏的。似乎它应该产生警告。另外,感谢您验证我的回答,您的文章很有帮助。
  • 假设我们产生了一个警告。 如果需要该行为,您将如何关闭警告?我们尝试为极有可能是错误的行为保留警告,并且如果这是您的行为想要,有一种方法可以编写代码,以便警告消失。这既不符合标准;该行为很可能是正确的,如果是,则无法编写代码说“不,真的,我是认真的,停止警告我”。结果是,在许多函数调用中,您会在它们周围使用编译指示来抑制警告,这很丑陋。
  • 好点。但是,完全隐藏方法会产生警告 (0114)。有问题的隐藏会安静地编译并导致不可见的隐藏成员 - 并且可能是运行时错误。为什么不至少警告这种隐藏级别(并允许新关键字同样工作)?我敢肯定这种隐藏对于编译器来说更难找到,因为它不仅仅是签名匹配,还有参数基类型发现;但是,故意以这种方式隐藏似乎有点太聪明了,不是好的设计,而且我认为以这种方式隐藏更有可能是错误而不是设计。
  • 如果“新”不存在我们给出警告的原因是因为这表明隐藏是偶然的。我们不希望意外隐藏成为一个错误,因为那又是一个脆弱的基类失败;你升级你的基类并且你的派生类没有编译,因为基类作者添加了一个你现在隐藏的成员。您可以通过说“是的,我是认真的,我说的是‘新’”来关闭警告。
【解决方案3】:

这是编译器的结果,我们检查了IL代码。

【讨论】:

  • 是的,但由于规范,它是这样的。
【解决方案4】:

原因是因为它是模棱两可的。编译器只需要决定一个。有人认为间接的越少越好(性能可能是一个原因)。 如果开发者只是写了:

((Base)d).Foo (i);

很清楚,给你预期的结果。

【讨论】:

    【解决方案5】:

    原因是:性能。 调用虚方法需要更多时间。在虚拟方法上调用委托需要更多时间等等......

    见: The cost of method calls

    【讨论】:

    • 真的吗?虽然关于通话费用的信息非常有趣,毫无疑问会对许多决策产生影响,但我不确定我能否看到这两个问题之间的直接联系。是的,他们选择了非虚拟作为默认值,因为方法调用性能原因没有定义,这是否真的在很大程度上决定了重载解决方案,以至于他们选择了我和其他一些人认为的东西“不直观”?我仍然不相信这是决定性的原因,但仍然感谢一个有趣的答案。 T
    • 绝对不是这个原因。
    猜你喜欢
    • 1970-01-01
    • 2020-07-31
    • 2020-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-03
    • 2017-05-30
    • 1970-01-01
    相关资源
    最近更新 更多