C#语言规范说如果我继承了一个类,并且基类和派生类具有相同签名的相同命名成员,那么我必须使用new
关键字来隐藏基类成员(在base和派生类成员中使用virtual和override关键字还有另一种方法)。
但实际上我发现派生类auto隐藏了派生成员,如果它具有相同的命名成员。那么同一个命名派生类成员中新关键字的主要好处和问题是什么?
答案 0 :(得分:27)
新的不是必需,正如您所注意到的那样。它是可选,如果您不使用它,则会收到警告。你完全正确地注意到这是一个奇怪的设计决定。
此设计决策的目的是帮助缓解一类被称为“脆弱基类”问题的问题。这是该问题的一个版本:
Foo Corporation创建了一个类Frobber并将其发布在Foo.DLL 1.0版中:
namespace FooCorp
{
public class Frobber
{
public void Frobnicate() { ... }
...
你工作的Bar公司制作Blobbers。 Blobber可以做Frobber可以做的所有事情,但此外,它也可以做Blobnicate。所以你决定从FooCorp重新使用Frobnicate的实现,并添加一些额外的功能:
namespace BarCorp
{
public class Blobber : FooCorp.Frobber
{
public void Blobnicate() { ... }
...
Foo公司意识到人们喜欢Blobnicate,他们决定发货Foo.DLL v2.0:
namespace FooCorp
{
public class Frobber
{
public void Frobnicate() { ... }
public void Blobnicate() { ... }
...
当您获得新版本的Foo.DLL并重新编译时,您希望被告知您现在意外地引入了一种影响基类方法的新方法。这可能是一件危险的事情去做;你的类是在假设基类是Frobnicator的情况下编写的,但显然现在它也是一个Blobnicator!这个事实可能会破坏您的客户,他们在打算调用派生类版本时可能会意外调用基类版本。
我们将“new”设为可选,以便您可以 legal 在不更改源代码的情况下隐藏基类方法。如果我们将其设为非法,那么 FooCorp会因为升级而破坏您的构建。但我们会发出警告,以便您知道您可能会意外地执行此操作。然后,您可以仔细检查代码;如果您确定您的Blobnicate实现现在是多余的,则可以将其删除。如果仍然良好,您可以将其标记为“新”并消除警告。
有意义吗?这是C#的一个微妙特性,使其适用于大规模多版本面向组件的软件。
答案 1 :(得分:4)
使用new
的好处是让您的意图明确。
但是,除非您确实需要隐藏该成员,否则通常最好使用virtual/override
以便以多态方式使用该成员。通过隐藏,new
成员仅通过派生类的引用来使用。如果您通过基本引用工作,您将继续获得基本行为,并且可能是意外的。
class Foo
{
public void M() { Console.WriteLine("Foo"); }
}
class Bar : Foo
{
public new void M() { Console.WriteLine("Bar"); }
}
Bar bar = new Bar();
bar.M(); // writes Bar
Foo foo = new Bar(); // still an instance of Bar
foo.M(); // writes Foo, does not use "new" method defined in Bar
相反,如果方法已在virtual
中Foo
和override
中Bar
声明,那么方法调用将一直是" Bar&#34 ;在任何一种情况下。
答案 2 :(得分:3)
new
关键字可让您具有特定的意图。
虽然默认行为是隐藏没有new关键字的基类成员,但是无法确定是否真的想隐藏该成员,或者你是否真的想要覆盖该成员。
明确表达总是更好。这样,下一个开发人员就会确切地知道你的意图。