为什么要使用`new`隐藏方法?

可能重复:
C# – 方法签名中的新关键字

假设我有3个class:GrandDad,爸爸,儿子。 儿子inheritance自祖父,inheritance自祖父。

每个类都实现了foo。

// GrandDad class: public virtual void foo() // Dad class: new public virtual void foo() // Son class: public override void foo() 

我不明白为什么爸爸会使用关键字的原因。 据我所知,使用隐藏方法。 你为什么想做这个?

我阅读了新的MSDN解释,但讨论只是机械的,而不是架构的。

谢谢

您呈现的代码不是一个很好的示例,但“new”的一个常见用例是,如果修改了基类以添加新方法(通常是超出您控制范围的基类),但您现有的代码需要使用相同的名称调用派生类方法。 将派生类方法更改为“new”允许您与公共接口的现有使用者保持兼容。

希望以下示例为您提供了新关键字的用途。 这实际上取决于function的要求。

 public class Base { public virtual void SomeMethod() { } } public class Derived : Base { public override void SomeMethod() { } } ... Base b = new Derived(); b.SomeMethod(); 

如果覆盖Base.SomeMethod,将最终调用Derived.SomeMethod。

现在,如果使用new关键字而不是override ,派生类中的方法不会覆盖基类中的方法,它只是隐藏它。 在这种情况下,代码如下:

 public class Base { public virtual void SomeOtherMethod() { } } public class Derived : Base { public new void SomeOtherMethod() { } } ... Base b = new Derived(); Derived d = new Derived(); b.SomeOtherMethod(); d.SomeOtherMethod(); 

首先会调用Base.SomeOtherMethod,然后调用Derived.SomeOtherMethod。 它们实际上是两个完全独立的方法,它们碰巧具有相同的名称,而不是覆盖基本方法的派生方法。

当您在更多层(Control,Button,RedButton)上具有类层次结构并且您希望限制给定类(Button)的任何子类以更改从Controlinheritance的generics行为时,可能“有用”的场景,即由Button修改; 通过Button规则,而不是通过控制规则,RedButton可以成为TreeViewControl的其他方式:) …; 这可能在您inheritance实现时发生:)

还有其他技术,更干净,如“策略模式”(您聚合行为,而不是inheritance)用于处理前一个场景。

我将给出一个超越“它做什么”的例子,并在它有用时予以掩盖。

您是否需要将其中一个业务类作为容器? 例如,也许你想这样做:

 Person aperson = new Person(); aperson.Add(anAddress); aperson.Add(anAddress); 

如果希望Add()方法在插入时执行某些特定于业务的逻辑,则可以选择。 您可以自己实现容器function(yuck),也可以让Person类inheritance容器:

 public class Person : List
{ }

现在,您可以在两个条件下获得所需的行为:

  1. 不要通过其基类型(List)引用Person类,并且……
  2. 使用’new’关键字隐藏基本List’add’操作。

新关键字是必需的,因为List.Add(…)不是虚拟的。 这有点邪恶(可能很糟糕),但在这种特殊情况下大多很酷。 在您编写的“new Add(…)”方法中,包含业务逻辑,然后调用基本的Add(…)方法。

想让这个更酷吗? 做一棵树:

 public class Node : List { } 

在电子游戏中,我在编写游戏树时使用了这个技巧。

那么这就是你想要这样做的一个原因:

 // GrandDad: public void CanIWatchTv() { return age > 5; } // Dad: Grandpa is too liberal public override void CanIWatchTv() { return age > 12; } // Son: I don't care what dad says! public new void CanIWatchTv() { return true; } 

换句话说,当你完全想要覆盖(而不是关键字)基本方法正在做什么而不是扩展它时,你会使用new

在现实世界的情景中,它应该谨慎使用,因为它违背了inheritance原则(如果允许Son超越他的Dad – 答案取决于你是一个儿子还是一个父亲,但在一个完美的世界,它应该’是)。

我的理解是,主要动机之一与图书馆的版本化有关。

1月1日:X公司将Class Dad作为Super Library v1.0的一部分发布。

 class Dad { virtual public void Foo() { ... }; } 

2月1日:您购买Super Library v1.0并创建子类Son。

 class Son : Dad { public void Bar() { ... }; } 

3月1日:公司X发布了Super Library 2.0,添加了一个名为Bar的新方法。 他们不知道你还创建了一个方法Bar,他们的Bar完全不相关。

 class Dad { virtual public void Foo() { ... }; virtual public void Bar() { ... }; } 

5月1日:你购买Super Library v2.0并重新编译你的Son类。 令您惊讶的是,您发现他们添加了一个名为Bar的方法与您的方法冲突。 为了最大限度地降低回归风险,现在将Bar方法标记为方法,以区别于Company X的Bar。 虽然他们奇怪地拥有相同的名字,但两者并安地共存。 他们现有的代码将按预期调用他们的Bar,您现有的代码将按预期调用您的Bar。

 class Son : Dad { new public void Bar() { ... }; }