调用而不是派生基方法中的阴影
本文关键字:方法 阴影 派生 调用 | 更新日期: 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()
将被调用,根据我所读到的关于阴影的内容,应该调用来自Dog
的Foo()
。有人能解释一下我遗漏了什么吗?
我的例子是这样的: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方法。这里,从Animal
到Dog
类的转换是可能的,因为变量dog2
最初是从Dog类
在您的情况下,dog1
(即Dog
)通常会给您"Foo Dog",但因为您明确告诉它是Animal
,它会显示"Foo Animal"。有道理。
然后,使用dog2
,也就是Animal
,你会期望"Foo animal"开火,因为你说"嘿,你是一只动物",即使你在Animal
上有virtual
(这表明派生类应该覆盖这个方法,然后根据类型在运行时调用什么的解析会发生),你也会使用隐藏它的new
。
仍然完全可以。在他们的例子中,bcdc
是BaseClass
类型,但在运行时,由于它是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();
它总是调用基方法,因为它在派生中找不到被重写的方法。