C#-关键词的使用虚拟+复盖与新的
-
03-07-2019 - |
题
什么之间的差异,宣布一个方法中的一个基本类型"virtual
"然后压倒一切的其中一个孩子的类型使用的"override
"关键词,而不是简单地使用"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,如果您使用了覆盖,则打印为true。
(基本代码取自Joseph Daigle)
所以,如果你正在做真正的多态,你应该总是超越。您需要使用“新”的唯一地方当方法与基类版本没有任何关系时。
其他提示
我总是通过图片更容易理解这样的事情:
再次,采取joseph daigle的代码,
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();
注意:重要的是我们的对象实际上是一个 Bar
,但我们将它存储在 Foo
的变量中strong>(这类似于施法)
然后结果将如下,具体取决于您在声明类时是否使用 virtual
/ override
或 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
。
虚拟/覆盖告诉编译器这两个方法是相关的,在某些情况下,如果你认为你正在调用第一个(虚拟)方法,那么调用第二个(被覆盖的)实际上是正确的方法而不是。这是多态性的基础。
(new SubClass() as BaseClass).VirtualFoo()
将调用SubClass的覆盖VirtualFoo()方法。
new 告诉编译器您要向派生类添加一个方法,该方法的名称与基类中的方法相同,但它们之间没有任何关系。
(new SubClass() as BaseClass).NewBar()
将调用BaseClass的NewBar()方法,而不是:
(new SubClass()).NewBar()
将调用SubClass的NewBar()方法。
除了技术细节之外,我认为使用虚拟/覆盖可以在设计上传达大量的语义信息。声明方法虚拟时,表明您希望实现类可能希望提供自己的非默认实现。同样地,在基类中省略这一点,声明期望默认方法应该足以满足所有实现类。类似地,可以使用抽象声明来强制实现类来提供自己的实现。同样,我认为这传达了很多关于程序员如何期望使用代码的信息。如果我正在编写基础和实现类,并发现自己使用新的,我会认真地重新考虑不要在父级中使方法虚拟并明确声明我的意图。
new
关键词是为躲藏。-意味着你隐藏自己的方法在运行时间。产出将是基于基类方法。override
为压倒一切的.-意味着你是用你的派生类方法的参考的基类。产出将是基于源类方法。
我的解释版本来自于使用属性来帮助理解差异。
override
很简单,对吗?底层类型会覆盖父级。
new
可能是误导性的(对我而言)。有了属性,它更容易理解:
public class Foo
{
public bool GetSomething => false;
}
public class Bar : Foo
{
public new bool GetSomething => true;
}
public static void Main(string[] args)
{
Foo foo = new Bar();
Console.WriteLine(foo.GetSomething);
Bar bar = new Bar();
Console.WriteLine(bar.GetSomething);
}
使用调试器你可以注意到 Foo foo
有 2 GetSomething
属性,因为它实际上有2个版本的属性, Foo
和 Bar
,并知道要使用哪一个,c#" picks"当前类型的属性。
如果您想使用Bar的版本,您可能会使用覆盖或使用 Foo foo
。
条形码
只有 1 ,因为它需要 GetSomething
的完全新行为。
不用任何方法标记方法:使用对象的编译类型绑定此方法,而不是运行时类型(静态绑定)。
使用 virtual
标记方法意味着:使用对象的运行时类型绑定此方法,而不是编译时间类型(动态绑定)。
在派生类中使用 override
标记基类 virtual
方法意味着:这是使用对象的运行时类型(动态绑定)绑定的方法。
在派生类中使用 new
标记基类 virtual
方法意味着:这是一个新方法,与基础中具有相同名称的方法无关class,它应该使用object的编译时类型(静态绑定)绑定。
在派生类中未标记基类 virtual
方法意味着:此方法标记为 new
(静态绑定)。
标记方法 abstract
意味着:此方法是虚拟的,但我不会为它声明一个主体,它的类也是抽象的(动态绑定)。