【问题标题】:benefit of using new keyword in derived class member having same name with base class member在与基类成员同名的派生类成员中使用 new 关键字的好处
【发布时间】:2012-01-03 23:26:20
【问题描述】:

C#语言规范说,如果我继承一个类,并且基类和派生类具有相同的命名成员和相同的签名,那么我必须使用new关键字来隐藏基类成员(有另一种方法是在基类和派生类成员中使用 virtual 和 override 关键字)。

但在实践中,我发现如果派生类具有相同的命名成员,则派生类会自动隐藏派生成员。那么在同名派生类成员中新关键字的主要好处和问题是什么?

【问题讨论】:

标签: c#


【解决方案1】:

new 关键字可让您明确自己的意图。

虽然默认行为是在不使用 new 关键字的情况下隐藏基类的成员,但无法判断您是否真的想要隐藏该成员,或者您是否真的想要覆盖该成员。

明确一点总是更好。这样,下一个开发人员就会确切地知道您的意图。

【讨论】:

    【解决方案2】:

    使用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
    

    如果在Foo 中使用virtual 声明该方法,在Bar 中使用override 声明该方法,那么无论哪种情况,方法调用都将始终为“Bar”。

    【讨论】:

      【解决方案3】:

      New 不是必需的,正如您所指出的。它是可选的,如果你不使用它,你会得到一个警告。您完全正确地注意到,乍一看这是一个奇怪的设计决定。

      此设计决策的目的是帮助缓解称为“脆性基类”问题的一类问题。这是该问题的一个版本:

      Foo Corporation 创建了一个 Frobber 类并在 Foo.DLL 版本 1.0 中发布它:

      namespace FooCorp
      {
        public class Frobber
        {
          public void Frobnicate() { ... }
          ...
      

      您为之工作的 Bar Corporation 生产 Blobbers。 Blobber 可以做 Frobber 可以做的所有事情,但除此之外,它也可以 Blobnicate。所以你决定重用 FooCorp 的 Frobnicate 实现,并添加一些额外的功能:

      namespace BarCorp
      {
        public class Blobber : FooCorp.Frobber
        {
          public void Blobnicate() { ... }
          ...
      

      Foo Corporation 意识到人们喜欢 Blobnicate,因此他们决定发布 Foo.DLL v2.0:

      namespace FooCorp
      {
        public class Frobber
        {
          public void Frobnicate() { ... }
          public void Blobnicate() { ... }
          ...
      

      当你得到一个新版本的 Foo.DLL 并重新编译时,你想被告知你现在不小心引入了一个隐藏基类方法的新方法。这可能是一件危险的事情去做;您的类是在假设基类是 Frobnicator 的情况下编写的,但显然现在它也是 Blobnicator !这一事实可能会破坏您的客户,他们可能会在打算调用您的派生类版本时意外调用基类版本。

      我们将“new”设为可选,以便您在不更改源代码的情况下合法隐藏基类方法。如果我们将其设为非法,那么 FooCorp 的升级会破坏您的构建。 但我们将其设为警告,以便您知道您可能会不小心这样做。然后您可以仔细检查代码;如果你决定你的 Blobnicate 实现现在是多余的,你可以删除它。如果还不错,可以将其标记为“新”并消除警告。

      有意义吗?这是 C# 的微妙特性之一,使其适用于大型多版本面向组件软件。

      【讨论】:

        猜你喜欢
        • 2016-05-21
        • 1970-01-01
        • 2017-11-08
        • 2022-01-25
        • 1970-01-01
        • 1970-01-01
        • 2018-11-30
        • 2013-02-05
        • 2017-05-10
        相关资源
        最近更新 更多