调用而不是派生基方法中的阴影

本文关键字:方法 阴影 派生 调用 | 更新日期: 2023-09-27 17:59:07

我正试图弄清楚c#中阴影的概念。这是我的代码,它没有像我预期的那样运行:

public class Animal
{
    public virtual void Foo()
    {
        Console.WriteLine("Foo Animal");
    }
}
public class Dog : Animal
{
    public new void Foo()
    {
        Console.WriteLine("Foo Dog");
    }
}
class Program
{
    static void Main(string[] args)
    {
        Dog dog1 = new Dog();
        ((Animal)dog1).Foo();
        Animal dog2 = new Dog();
        dog2.Foo();
    }
}

当执行Main中的代码时,来自基类(Animal)的Foo()将被调用,根据我所读到的关于阴影的内容,应该调用来自DogFoo()。有人能解释一下我遗漏了什么吗?

我的例子是这样的:https://msdn.microsoft.com/en-us/library/ms173153.aspx

更新:这是msdn:中的示例

class Program
{
    static void Main(string[] args)
    {
        BaseClass bc = new BaseClass();
        DerivedClass dc = new DerivedClass();
        BaseClass bcdc = new DerivedClass();
        // The following two calls do what you would expect. They call
        // the methods that are defined in BaseClass.
        bc.Method1();
        bc.Method2();
        // Output:
        // Base - Method1
        // Base - Method2

        // The following two calls do what you would expect. They call
        // the methods that are defined in DerivedClass.
        dc.Method1();
        dc.Method2();
        // Output:
        // Derived - Method1
        // Derived - Method2

        // The following two calls produce different results, depending 
        // on whether override (Method1) or new (Method2) is used.
        bcdc.Method1();
        bcdc.Method2();
        // Output:
        // Derived - Method1
        // Base - Method2
    }
}
class BaseClass
{
    public virtual void Method1()
    {
        Console.WriteLine("Base - Method1");
    }
    public virtual void Method2()
    {
        Console.WriteLine("Base - Method2");
    }
}
class DerivedClass : BaseClass
{
    public override void Method1()
    {
        Console.WriteLine("Derived - Method1");
    }
    public new void Method2()
    {
        Console.WriteLine("Derived - Method2");
    }
}

当执行bcdc.Method1()时,会调用派生类中的Method1(),而在我的示例中并非如此。

调用而不是派生基方法中的阴影

在行((Animal)dog1).Foo()中,首先将对象dog1转换为Animal from Dog类型。所以它调用基类Animal中的方法。

如果您在dog类的Foo方法中使用override而不是new关键字,您将获得预期结果(即,将调用dog类的Foo方法)。

在代码Animal dog2 = new Dog();中,dog2将被创建为Animal的对象,而不是Dog。因此,调用Foo方法将调用Animal类中的方法。

您可以使用以下代码((Dog)dog2).Foo();调用Dog类中的Foo方法。这里,从AnimalDog类的转换是可能的,因为变量dog2最初是从Dog类

构造函数创建的

在您的情况下,dog1(即Dog)通常会给您"Foo Dog",但因为您明确告诉它是Animal,它会显示"Foo Animal"。有道理。

然后,使用dog2,也就是Animal,你会期望"Foo animal"开火,因为你说"嘿,你是一只动物",即使你在Animal上有virtual(这表明派生类应该覆盖这个方法,然后根据类型在运行时调用什么的解析会发生),你也会使用隐藏它的new


仍然完全可以。在他们的例子中,bcdcBaseClass类型,但在运行时,由于它是Derived类型,AND Method1在基础上使用virtual AND override,并派生,因此它被调用。

因为它的method2没有覆盖虚拟机,所以它调用它所知道的唯一一个,Base。如果不是将其定义为BaseClass,而是DerivedClass,它会发现它是method2

在您执行((Animal)dog1).Foo()dog2.Foo()的示例中,Animal的Foo方法会被执行,因为当您运行应用程序CLR时,首先搜索基中的实现(因为引用了Animal),然后检查它是否在派生类型中被重写,由于您没有重写基类实现,因此在这两种情况下,它都调用基方法(Animal的Foo),而不是派生的(Dog的Foo。

更新:

override和new关键字之间的差别很小。当您进行重写时,无论您使用的是哪个引用,当对象为派生类型时,它总是调用重写的方法。如果您没有重写新关键字,那么实际上是在隐藏基类实现我的意思是,你隐藏了派生类型基类的实现,而不是基类,所以当你为派生对象使用基类的引用时,比如
Base obj = new Derived();它总是调用基方法,因为它在派生中找不到被重写的方法。