为什么我们需要new关键字,为什么要隐藏而不是覆盖默认行为?

San*_*box 79 c# overriding

我正在看这篇博文,并有以下问题:

  • 为什么我们需要new关键字,只是指定隐藏基类方法.我的意思是,为什么我们需要它?如果我们不使用override关键字,是不是我们隐藏了基类方法?
  • 为什么隐藏C#中的默认值而不是覆盖?为什么设计师会这样实现它?

Eri*_*ert 126

好问题.让我重申一下.

为什么用其他方法隐藏方法是合法的?

让我用一个例子回答这个问题.您有CLR v1的界面:

interface IEnumerable
{
    IEnumerator GetEnumerator();
}
Run Code Online (Sandbox Code Playgroud)

超.现在在CLR v2中你有泛型并且你认为"伙计,如果我们在v1中已经有了泛型,我会把它变成一个通用接口.但我没有.我现在应该做一些与它兼容的东西,这通用的,所以我从泛型中获益,而不会失去与期望IEnumerable的代码的向后兼容性."

interface IEnumerable<T> : IEnumerable
{
    IEnumerator<T> .... uh oh
Run Code Online (Sandbox Code Playgroud)

你打算怎么称呼GetEnumerator方法IEnumerable<T>?请记住,您希望它在非通用基接口上隐藏GetEnumerator.你永远不会想被称为那个东西,除非你在一个向后compat的情况是明确的.

仅这就证明方法隐藏是正确的.有关方法隐藏的理由的更多想法,请参阅我关于该主题的文章.

为什么没有"新"的隐藏会引起警告?

因为我们想要引起你注意你隐藏的东西,并且可能会意外地做到这一点.请记住,由于对其他人完成的基类编辑,而不是编辑派生类,您可能会意外地隐藏某些内容.

为什么没有"新"隐藏而不是错误?

同样的道理.您可能会意外地隐藏某些内容,因为您刚刚选择了基类的新版本.这事儿常常发生.FooCorp创建了一个基类B.BarCorp使用方法Bar生成派生类D,因为他们的客户喜欢这种方法.FooCorp看到了,并说,嘿,这是一个好主意,我们可以将该功能放在基类上.他们这样做并发布了新版本的Foo.DLL,当BarCorp选择新版本时,如果他们被告知他们的方法现在隐藏了基类方法,那就太好了.

我们希望这种情况是警告而不是错误,因为将其作为错误意味着这是脆弱的基类问题的另一种形式.C#经过精心设计,以便当有人对基类进行更改时,对使用派生类的代码的影响最小化.

为什么要隐藏而不是覆盖默认值?

因为虚拟覆盖是危险的.虚拟覆盖允许派生类更改已编译为使用基类的代码的行为.做一些危险的事情,比如做一个覆盖应该是你有意识和有意识做的事情,而不是偶然的.


Inc*_*ito 15

如果派生类中的方法前面带有new关键字,则该方法被定义为独立于基类中的方法

但是,如果未指定new或覆盖,则结果输出与指定new相同,但是您将收到编译器警告(因为您可能不知道您在基类方法中隐藏了一个方法,或者你可能想要覆盖它,而只是忘了包含关键字).

因此,它可以帮助您避免错误并明确显示您想要执行的操作,并使代码更易读,因此可以轻松理解您的代码.


Hen*_*man 12

值得注意的是,在这种情况下唯一的影响new是抑制警告.语义没有变化.

所以一个答案是:我们需要new向编译器发出信号,告知隐藏是有意的并且要消除警告.

后续问题是:如果您不能/不能覆盖方法,为什么要引入另一个具有相同名称的方法?因为隐藏本质上是名称冲突.在大多数情况下,你当然会避免它.

我可以想到故意隐藏的唯一理由是当一个名称被一个接口强加给你时.


Dar*_*rov 5

在C#中,默认情况下密封成员,这意味着您不能覆盖它们(除非使用virtualabstract关键字标记),这是出于性能原因.该new修饰符是用来明确隐藏继承成员.

  • 但是你什么时候真的想使用新修饰符? (3认同)
  • 当您想要显式隐藏从基类继承的成员时。隐藏继承的成员意味着该成员的派生版本将替换基类版本。 (2认同)
  • 但是使用基类的任何方法仍将调用基本实现,而不是派生.这对我来说似乎是一种危险的情况. (2认同)