为什么标记为在基类中隐藏实现的方法可以调用隐藏方法?

本文关键字:方法 隐藏 调用 实现 基类 为什么 记为 | 更新日期: 2023-09-27 18:18:23

我一直在做一些关于c#规范的阅读,并遇到了一个我没有预料到的场景,希望有人能分享一些启示。

我偶然发现了new关键字,用于在派生类中隐藏基类的成员,随后讨论了何时在virtual成员上使用new而不是override

我把一小段代码示例扔到我的IDE中,期望看到一个编译错误

public class BaseType
{
    public void method()
    {
        // do nothing
    }
}
public class DerivedType : BaseType
{
    public new void method()
    {
        base.method();
    }
}

却发现这是合法的c#。既然派生类隐藏了method()的存在,为什么我仍然被允许调用它?

欢呼

为什么标记为在基类中隐藏实现的方法可以调用隐藏方法?

DerivedType对将继承DerivedType的类隐藏了方法,而不是从自身隐藏了方法。
注意,要隐藏方法,类必须知道在它的父类中存在一个具有相同名称和相同参数的方法。因此,一个类在它自己的作用域中隐藏方法在逻辑上是不正确的。

不要将方法隐藏与方法重写混合使用。他们是两种完全不同的动物。

当隐藏一个方法时,只有在通过隐藏该方法开头的类型访问该方法时才会隐藏它:

public class Foo
{
    public string Blah() { return "Hi from Foo!"; }
}
public class DerivedFoo: Foo
{
    public new string Blah() { return "Hi from DerivedFoo!"; }
}

现在我们有了以下行为:

void TestFoos()
{
    Foo foo = new Foo();
    DerivedFoo derivedFoo = new DerivedFoo();
    Foo derivedFooInDisguise = derivedFoo as Foo;
    Console.WriteLine(foo.Blah()); //Outputs "Hi from Foo!"
    Console.WriteLine(derivedFoo.Blah()); //Outputs "Hi from DerivedFoo!"
    Console.WriteLine(derivedFooInDisguise.Blah()); //Outputs "Hi from Foo!" 
}

注意,即使将Blah声明为virtual,此行为也是相同的。有趣的部分是第三个电话。该方法是通过Foo类型的对象调用的。因为不是虚调用,所以会调用Foo.Blah(),而不是DerivedFoo.Blah()

现在,这与方法重写完全不同,在中,虚拟方法调用总是解析到对象的运行时类型,而不是调用它时的类型:

public class Foo
{
    public virtual string Blah() { return "Hi from Foo!"; }
}
public class DerivedFoo: Foo
{
    public override string Blah() { return "Hi from DerivedFoo!"; }
}

现在我们有了以下行为:

void TestFoos()
{
    Foo foo = new Foo();
    DerivedFoo derivedFoo = new DerivedFoo();
    Foo derivedFooInDisguise = derivedFoo as Foo;
    Console.WriteLine(foo.Blah()); //Outputs "Hi from Foo!"
    Console.WriteLine(derivedFoo.Blah()); //Outputs "Hi from DerivedFoo!"
    Console.WriteLine(derivedFooInDisguise.Blah()); ////Outputs "Hi from DerivedFoo!"
}