继承中的重载方法 类

Overloading methods in inherited classes

我已经开始明白我不明白是怎么回事了。在 C# 中存在以下行为:

public class Base
{
    public void Method(D a)
    {
        Console.WriteLine("public void Method(D a)");
    }
}

public class Derived: Base
{
    public void Method(B a)
    {
        Console.WriteLine("public void Method(B a)");
    }
}

public class B { }

public class D: B { }

class Program
{
    static void Main(string[] args)
    {
        Derived derived = new Derived();
        D d = new D();

        derived.Method(d);
    }
}

它将打印

public void Method(B a)

而不是

public void Method(D a)

令人惊讶。我想这种行为的原因是方法 table 的实现。如果 CLR 在当前类型中找到相应的方法,则不会在基 class 中搜索方法。我认为他们正在努力提高性能。

但是我对下面的代码完全失望了:

public class Base
{
    public virtual void Method(D a)
    {
        Console.WriteLine("public void Method(D a)");
    }
}

public class Derived: Base
{
    public override void Method(D a)
    {
        Console.WriteLine("public override void Method(D a)");
    }

    public void Method(B a)
    {
        Console.WriteLine("public void Method(B a)");
    }

}

public class B { }

public class D: B { }

class Program
{
    static void Main(string[] args)
    {
        Derived derived = new Derived();
        D d = new D();

        derived.Method(d);
    }
}

它将打印

public void Method(B a)

而不是

public override void Method(D a)

这很糟糕而且非常不可预测table。

谁能解释一下?

我假设方法table有只在当前类型中实现的方法(不包括覆盖方法),一旦找到任何可以调用的方法,CLR就会停止寻找相应的方法.我说得对吗?

I have started to understand that I do not understand what is going on.

智慧由此开始。

It's awful and very unpredictable.

两者都不是。相比之下,该功能旨在通过 消除脆性基础 class 失败的原因来 减少 不可预测性。

Can anyone explain it?

请参阅我 2007 年关于该主题的文章。

https://blogs.msdn.microsoft.com/ericlippert/2007/09/04/future-breaking-changes-part-three/

虽然简短的版本是:派生 class 中的方法总是比基 class 中的方法好;编写派生 class 的人比编写基地 class.

Servy 指出我没有涵盖您的第二点。为什么派生 class 中的覆盖不会使 "D" 方法 "in the derived class"?

虚拟方法被认为是声明它们的 class 的 方法 ,而不是声明它们的 class 的 方法最近被覆盖。为什么?因为 选择覆盖与否是 class 的实现细节,而不是 public 表面区域的一部分。

我的意思是,考虑一下。你写了一些代码,它起作用了,然后你说,嘿,我要在这个类型层次结构中某处重写这个方法,突然改变 过载分辨率 到其他地方?这正是 C# 试图消除的那种脆弱性。

请记住,C# 是为 一个代码由团队编辑的世界 精心设计的。奇怪的是,许多现代语言的设计就好像一个人在编写所有代码,而且他们一次就把它弄对了;那是不现实的。 C# 的一些更不寻常的功能,例如您发现的功能,可以帮助您保持程序行为可预测,即使其他人正在编辑您的基础 classes。

我可以看出这里的混乱。埃里克的回答可以用一个例子来更好地说明。如果您按如下方式更改代码...

public class Base
{
    public virtual void Method(D a)
    {
        Console.WriteLine("public void Method(D a)");
    }

    public void Method(B a)
    {
        Console.WriteLine("public void Method(B a)");
    }
}

public class Derived : Base
{
    public override void Method(D a)
    {
        Console.WriteLine("public override void Method(D a)");
    }

}

public class B { }

public class D : B { }

输出变为"public override void Method(D a)"。

为什么?

如 Eric 的文章所述...

methods in a base class are not candidates if any method in a derived class is applicable

由于 Method(D) 和 Method(B) 现在都在基础 class 中,Method(D) 已成为最接近的匹配项,它在派生的 class 中被覆盖,因此输出.

对新手来说很混乱吗?对于有经验的开发人员来说,这也很令人困惑。我认为这里要说明的关键是你这里的设计不好,我不是在谈论 CLR 或 C# 编译器,它已经尽力帮助你了,我在谈论 class在你的例子中。

我认为许多刚接触 OOP 的人常犯的一个错误是过度使用继承这一新玩具。继承通常不是 OOD 中使用的首选关系。当您开始研究 OOP 设计模式时,您会注意到许多模式不使用继承。

为什么?因为您的示例说明了使用继承时可能造成的混淆,所以它被称为 Fragile Inheritance。设计模式更经常使用聚合和组合将问题 space 分解为更可行、更可扩展和更易于管理的解决方案。

继承是一种强大的结构,与最强大的事物一样,应谨慎使用。