为什么要使用`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 { }
现在,您可以在两个条件下获得所需的行为:
- 不要通过其基类型(List)引用Person类,并且……
- 使用’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() { ... }; }