扩展方法和静态方法在c#中不匹配原型匹配

alg*_*mus 3 c# methods inheritance static

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

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当.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'.

Eri*_*ert 10

首先,你的"问题"明确是一个讨论的呼吁.因此,它将被关闭,因为征集讨论不是一个问题.StackOverflow不是讨论网站; 您可以使用任意数量的论坛进行讨论.这是一个提问的好地方.

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

  • 重载决策是以静态方法的形式确定调用a.To()具有适用的候选者.
  • 该方法是静态但接收器是实例的事​​实不会使候选者不适用.相反,它使重载决策错误选择它作为最佳适用候选者.
  • 除非没有适用的候选人,否则不会检查扩展方法.还有就是适用的候选人,尽管不合法的,因此不确认的扩展方法.

我同意这有点奇怪,但分析既正确又可取.语言设计者必须决定什么是更有可能的:调用者打算调用静态方法但是错误输入"a"代表"A",或者调用者打算调用一些完全不同的方法,这些方法可能扩展某些类型与"一个".更安全的假设是前者,因此我们给出了错误.

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

C#中的重载分辨率最初设计用于处理非常简单的语言; "params"是重载决策中最复杂的部分.它现在必须处理泛型,类型推断,扩展方法,动态,命名和可选参数.所有这些变化都严重强调了重载决策算法,因为每次添加新功能时,我们必须确保旧功能继续工作.

关于你的具体情况:如果你这样做会伤害,那就不要这样做了.制作具有相同名称的静态,实例和扩展方法是一个非常糟糕的主意.他们不太可能做同样的事情,所以不要让他们有相同的名字.

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

废话.编译器会告诉您确切的错误:重载决策选择了静态方法,并使用实例作为接收器调用它.这是程序中的错误,这是报告的错误.