【问题标题】:Extension methods and static methods mismatch prototype matching in c# [closed]c#中的扩展方法和静态方法不匹配原型匹配[关闭]
【发布时间】:2012-02-08 02:50:50
【问题描述】:

遇到了更高级的扩展和静态方法的冲突问题,我举例并简化了一些代码:

using System;

namespace Test
{
    static class EM
    {
        public static string To(this object o)
        {
            return o.GetType().ToString();
        }
    }
    class A
    {
        public static string To() { return "Test.A"; }
    }
    class B { }

    class Program
    {
        public static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            object o = null;
            o.To();
            B b = null;
            b.To();
            A a = null;
            a.To();
            A.To();
        }
    }
}

当 .NET 编译器(从 3.x 到 4.y)未能解决应该在“a.To();”出现的行中调用哪个方法时,我感到很惊讶。当然,我解释了编译器,但这就是可以带来错误消息的内容(字面意思是“Member 'Test.A.To()' cannot be accessed with an instance reference; qualify it with a type name instead”)。

我发布这篇文章是因为没有详细说明编译器为何会提醒程序员(已经知道规则),而是更多地促进讨论,​​以接近或最终解决此类问题(考虑帐户继承)在 Microsoft 之前,人类可以轻松判断扩展/静态方法调用匹配,而编译器甚至不提供确切的程序员错误描述或提示。

期待听到“stackoverflowers”的消息。

【问题讨论】:

  • 你说它在a.To() 上失败了,但是你引用的错误消息说A.To()。你的意思是什么?
  • @Shymep - 你是对的 - 请忽略我之前的评论。
  • 但这甚至与扩展方法无关是吧。如果您尝试使用对实例的引用来调用任何静态方法,您将收到相同的错误消息。扩展方法的存在不应突然改变类型本身的行为。
  • @BrianRasmussen 但是如果人们认为(错误但合理地)静态方法不是重载解决方案的“适用候选者”,则可以合理地期望选择扩展方法。在我看来,一个在给定上下文中不能合法调用的方法在重载决议的候选集中不会被考虑在我看来当然是合理的。甚至 Eric Lippert 也称这些规则“令人困惑”。
  • @phoog:我并不是说这并不令人困惑,我同意 Eric 比我解释得更好。

标签: c# inheritance methods static


【解决方案1】:

首先,您的“问题”明确要求进行讨论。因此它将被关闭,因为呼吁讨论不是问题。 StackOverflow 不是讨论网站;您可以使用任意数量的论坛进行讨论。这是提问的好地方。

澄清情况:这里发生的事情是:

  • 重载解决方法是确定调用a.To() 具有静态方法形式的适用候选
  • 方法是静态的但接收者是一个实例这一事实不会使候选者不适用。相反,它使得重载决议选择它作为最佳适用候选者是一个错误。
  • 除非没有适用的候选方法,否则根本不会检查扩展方法。 一个适用的候选者,尽管是非法的,所以扩展方法没有被检查。

我同意这有点奇怪,但分析是正确和可取的。语言设计者必须决定什么更有可能:调用者打算调用静态方法但错误地将“a”键入为“A”,或者调用者打算调用一些完全不同的方法可能会扩展一些与“a”兼容的类型。更安全的假设是前者,因此我们给出错误。

我知道有些人可能会觉得这种分析有些奇怪。这有点奇怪,但确实有道理。如果您认为这些规则晦涩难懂,那您是对的。当您在十多年的时间内将新规则应用于现有算法时,就会发生这种情况。

C# 中的重载解析最初是为处理一种非常简单的语言而设计的; “参数”是重载解析中最复杂的部分。它现在必须处理泛型、类型推断、扩展方法、动态以及命名和可选参数。所有这些更改都严重强调了重载解决算法,因为每次添加新功能时,我们都必须确保旧功能继续以同样的方式工作。

关于您的具体情况:如果您这样做时会感到疼痛,那么不要这样做。制作具有相同名称的静态、实例和扩展方法是一个非常糟糕的主意。他们不太可能做同样的事情,所以不要让他们有相同的名字

编译器甚至不提供确切的程序员错误描述或提示。

废话。编译器会准确地告诉你哪里出了问题:重载决议选择了一个静态方法,你用一个实例作为接收者来调用它。那是程序的错误,就是报的错误。

【讨论】:

  • 使用最近的 C# 编译器,这已经被我多年前的想法所认可,现在您可以调用与静态方法具有相同签名的扩展方法。我想知道语言本身发生了什么变化,导致你的推理无效。
猜你喜欢
  • 2016-01-29
  • 1970-01-01
  • 1970-01-01
  • 2019-04-24
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2015-08-12
  • 1970-01-01
相关资源
最近更新 更多