【问题标题】:Why overloaded methods have lower priority than instance method为什么重载方法的优先级低于实例方法
【发布时间】:2012-08-24 13:39:05
【问题描述】:

我有基类A

public class A
{
    public virtual void Method(A parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
    public virtual void Method(B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

继承B

public class B : A
{
    public virtual void Method(object parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }

    public override void Method(A parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }

    public override void Method(B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

带有扩展方法的静态类S

public static class S
{
    public static void Method(this B instance, B parameter)
    {
        Console.WriteLine(MethodBase.GetCurrentMethod());
    }
}

例如我们创建B类型的实例并在其上调用Method,我们期望它是public override void Method(B parameter)实际结果是public virtual void Method(object parameter)

var b = new B();
b.Method(new B()); // B.Method (Object parameter) Why???

为什么编译器不选择更合适的方法??? UPD 为什么它不是扩展方法?

【问题讨论】:

  • B 不是嵌套的而是继承的。
  • 如果对象具有同名的方法,则不会调用扩展方法。这是为了避免破坏旧代码,期望调用旧方法而不是新扩展。

标签: c# .net overloading overriding


【解决方案1】:

为什么编译器不选择更合适的方法?

因为它遵循语言规范的规则,在找到候选方法时,任何在基类中最初声明的候选方法(如果它们在派生类中被覆盖)都会被忽略,除非派生类没有任何适用的方法,否则搜索会向上移动到基类等。

这是designed to avoid the "brittle base class" problem,但面对派生类中被重写的方法,我觉得很难接受。

C# 4 规范的相关位是 7.4,以这个结尾:

对于类型参数和接口以外的类型中的成员查找,以及严格单继承的接口中的成员查找(继承链中的每个接口恰好有零个或一个直接基接口),查找规则的效果是只是派生成员隐藏了具有相同名称或签名的基成员。

编辑:关于扩展方法...

为什么它不是扩展方法?

来自规范的第 7.6.5.2 节:

在一种形式的方法调用(§7.5.5.1)中

expr . identifier ( )
expr . identifier ( args )
expr . identifier < typeargs > ( )
expr . identifier < typeargs > ( args )

如果调用的正常处理找不到适用的方法,则尝试将构造作为扩展方法调用处理

所以扩展方法只是作为最后的手段,基本上。

【讨论】:

  • 我觉得问题是为什么代码调用的是继承的方法,而不是扩展的方法,但是很难说?
  • @podiluska:我认为扩展方法是红鲱鱼。 OP 似乎不希望它被调用...
  • 为什么不调用扩展方法也很有趣。
  • @user854301:这很简单:成员查找步骤在“正常”查找失败后尝试查找扩展方法。
  • @Jon Skeet:我还是不明白。我已阅读有关“脆弱基类” 的文章并认为理解它。但是在这里我们已经覆盖了B 类中的方法,它们适合并且它们隐藏具有相同名称或签名的基成员,但是为什么编译器不想采用它们呢?如果你能举一些例子来说明为什么它以这种方式而不是另一种方式完成,我将不胜感激。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 2019-04-04
相关资源
最近更新 更多