我试图在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
中的代码时,会调用基类Foo()
中的Animal
,并从我读到的关于阴影的内容Foo()
来自{{应该调用1}}。有人可以解释我错过了什么吗?
我的例子是这样的: https://msdn.microsoft.com/en-us/library/ms173153.aspx
更新: 这是msdn的例子:
Dog
执行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()
,这在我的示例中并非如此。
答案 0 :(得分:0)
在您的情况下,dog1
Dog
通常会让您" Foo Dog",但因为您明确告诉它是Animal
,显示" Foo Animal"。有道理。
然后,使用dog2
Animal
,你会期待" Foo动物"解雇,因为你说'嘿,你是一个动物",即使你virtual
上有Animal
(这表明派生类应该覆盖这个方法,然后根据类型决定在运行时调用的内容,你可以使用隐藏它的new
。
还是完全可以。在他们的示例中,bcdc
的类型为BaseClass
,但在运行时,因为它是Derived
一个,而Method1
正在使用virtual
AND { {1}},在基础和派生上,它被调用。
因为它override
没有覆盖虚拟,所以它会调用它所知道的唯一一个, Base 。如果不是将其定义为method2
,而是BaseClass
,它就会发现它DerivedClass
答案 1 :(得分:0)
在您执行((Animal)dog1).Foo()
或dog2.Foo()
的示例中,动物的Foo方法被执行,因为当您运行应用程序时,CLR首先在base中搜索实现(因为对Animal的引用)然后检查它是否在派生类型中被覆盖,因为在这两种情况下,你没有覆盖它调用基本方法(Animal' Foo)而不是派生(Dog' Foo)的基类实现。 / p>
更新:
覆盖和新关键字之间的差异非常小。
当您执行覆盖时,无论您使用哪个引用都无关紧要,当对象为派生类型时,始终会调用重写方法。
如果你没有覆盖新的关键字,你实际上是在隐藏基类实现
我的意思是你在隐藏Derived类型的基类的实现而不是基础,所以当你使用base的引用来实现派生对象时
Base obj = new Derived();
它总是调用基本方法,因为它无法在派生中找到重写方法。
答案 2 :(得分:0)
在行System.Net.WebUtility.HtmlEncode()
中,首先将对象dog1转换为Dog from Dog类型。所以它在基类Animal中调用该方法。
如果您在狗类的 Foo 方法中使用覆盖而不是新关键字,您将获得预期结果(即,将调用 Dog 类的 Foo 方法。
在您的代码((Animal)dog1).Foo()
中,dog2将被创建为Animal dog2 = new Dog();
的对象,而不是Animal
。因此,调用Dog
方法将调用Foo
类中的方法。
您可以使用以下代码Animal
在 Dog 类中调用 Foo 方法。此处可以从((Dog)dog2).Foo();
转换为Animal
类,因为变量Dog
最初是从Dog类的构造函数