问题 为什么重载方法的优先级低于实例方法


我有基础课 A

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

Inhereted 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 为什么它不是扩展方法?


3300
2017-08-24 13:39


起源

B 不是嵌套但是继承。 - Henk Holterman
@Henk Holterman谢谢 - user854301
如果对象具有相同名称的方法,则不调用扩展方法。这是为了避免破坏旧代码,期望是调用旧方法而不是新扩展方法。 - Ankush


答案:


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

因为它遵循语言规范的规则,任何候选方法 最初宣布 在查找候选方法时,在基类中(如果它们在派生类中被重写)将被忽略,除非派生类没有任何适用的方法,此时搜索会移动到基类,等等。

这是 旨在避免“脆弱的基类”问题,但我发现在派生类中重写方法时难以接受。

C#4规范的相关位是7.4,以此结束:

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

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

为什么它不是扩展方法?

从规范的7.6.5.2节:

在其中一个表单的方法调用(第7.5.5.1节)中

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

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

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


10
2017-08-24 13:41



我认为问题是为什么代码调用继承的方法而不是扩展方法,但是很难说? - podiluska
@podiluska:我认为扩展方法是一个红鲱鱼。 OP似乎并不期望它被称为...... - Jon Skeet
有趣的是,为什么不调用扩展方法。 - user854301
@ user854301:那个很简单:成员查找步骤 只要 尝试在“正常”查找失败后找到扩展方法。 - Jon Skeet
@Jon Skeet:我仍然无法得到它。我读过有关的文章 “脆弱的基础类” 并认为理解它。但是在这里我们已经覆盖了方法 B 上课,他们适合他们 隐藏具有相同名称或签名的基本成员 但为什么编译器不想接受它们呢?如果你给出一些可以说明为什么以这种方式而不是另一种方式完成的例子,我将不胜感激。 - user854301