在基类型" virtual
"中声明方法然后使用" override
"关键字在子类型中覆盖它而不是new
在声明子类型中的匹配方法时简单地使用" "关键字之间有什么区别?
我总是通过图片更容易理解这样的事情:
再次,采取约瑟夫戴格尔的代码,
public class Foo { public /*virtual*/ bool DoSomething() { return false; } } public class Bar : Foo { public /*override or new*/ bool DoSomething() { return true; } }
如果你然后调用这样的代码:
Foo a = new Bar(); a.DoSomething();
注意:重要的是我们的对象实际上是a Bar
,但是我们将它存储在一个类型的变量中Foo
(这类似于转换它)
然后结果将如下,具体取决于您是否使用virtual
/ override
或new
何时声明您的类.
"new"关键字不会覆盖,它表示与基类方法无关的新方法.
public class Foo { public bool DoSomething() { return false; } } public class Bar : Foo { public new bool DoSomething() { return true; } } public class Test { public static void Main () { Foo test = new Bar (); Console.WriteLine (test.DoSomething ()); } }
这打印为false,如果你使用了override,它会打印为true.
(基本代码取自Joseph Daigle)
所以,如果你正在做真正的多态性,你应该总是过度.您需要使用"new"的唯一地方是该方法与基类版本无关.
以下是一些用于理解虚拟和非虚拟方法行为差异的代码:
class A { public void foo() { Console.WriteLine("A::foo()"); } public virtual void bar() { Console.WriteLine("A::bar()"); } } class B : A { public new void foo() { Console.WriteLine("B::foo()"); } public override void bar() { Console.WriteLine("B::bar()"); } } class Program { static int Main(string[] args) { B b = new B(); A a = b; a.foo(); // Prints A::foo b.foo(); // Prints B::foo a.bar(); // Prints B::bar b.bar(); // Prints B::bar return 0; } }
该new
关键字实际上创建了一个仅存在于该特定类型上的全新成员.
例如
public class Foo { public bool DoSomething() { return false; } } public class Bar : Foo { public new bool DoSomething() { return true; } }
该方法存在于两种类型中.当您使用反射并获取类型的成员时Bar
,您实际上会发现两个DoSomething()
看起来完全相同的方法.通过使用new
您有效地隐藏基类中的实现,以便当类派生自Bar
(在我的示例中)方法调用base.DoSomething()
转到Bar
而不是Foo
.
virtual/override告诉编译器这两个方法是相关的,并且在某些情况下,当您认为调用第一个(虚拟)方法时,实际上调用第二个(重写)方法是正确的.这是多态性的基础.
(new SubClass() as BaseClass).VirtualFoo()
将调用SubClass的覆盖VirtualFoo()方法.
new告诉编译器您要将方法添加到与基类中的方法同名的派生类,但它们彼此没有关系.
(new SubClass() as BaseClass).NewBar()
将调用BaseClass的NewBar()方法,而:
(new SubClass()).NewBar()
将调用SubClass的NewBar()方法.
除了技术细节之外,我认为使用虚拟/覆盖可以在设计上传达大量语义信息.声明方法虚拟时,表明您希望实现类可能希望提供自己的非默认实现.同样地,在基类中省略这一点,声明期望默认方法应该足以满足所有实现类.类似地,可以使用抽象声明来强制实现类来提供自己的实现.同样,我认为这传达了很多关于程序员如何期望使用代码的信息.如果我正在编写基础和实现类,并发现自己使用新的,我会认真地重新考虑不要在父级中使方法虚拟并明确声明我的意图的决定.