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

时间:2011-08-25 01:53:36

标签: c# architecture new-operator

  

可能重复:
  C# - new keyword in method signature

假设我有3个班:GrandDad,爸爸,儿子。儿子继承自祖父,继承自祖父。

每个类都实现了foo。

// GrandDad class: 
public virtual void foo()

// Dad class: 
new public virtual void foo()

// Son class: 
public override void foo()

我不明白为什么爸爸会使用 new 关键字。据我了解,使用 new 隐藏了一种方法。你为什么要这样做?

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

由于

6 个答案:

答案 0 :(得分:3)

您提供的代码不是一个很好的示例,但“new”的一个常规用例是修改基类以添加新方法(通常是您无法控制的基类),但是您有现有代码需要使用相同的名称调用派生类方法。将派生类方法更改为“新”可以使您与公共接口的现有使用者保持兼容。

答案 1 :(得分:0)

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

public class Base
{
    public virtual void SomeMethod()
    {
    }
}

public class Derived : Base
{
    public override void SomeMethod()
    {
    }
}

...

Base b = new Derived();
b.SomeMethod();

最终会调用Derived.SomeMethod,如果它重写Base.SomeMethod。

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

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。它们实际上是两个完全独立的方法,它们碰巧具有相同的名称,而不是覆盖基本方法的派生方法。

答案 2 :(得分:0)

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

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

答案 3 :(得分:0)

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

您的业务类是否需要成为容器?例如,您可能想要这样做:

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

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

public class Person : List<Address> { }

现在你可以在两个条件下得到你想要的行为:

  1. 不要通过其基类型(List)和...
  2. 引用Person类
  3. 使用'new'关键字隐藏基本列表'添加'操作。
  4. 新关键字是必需的,因为List.Add(...)不是虚拟的。这有点邪恶(可能很糟糕),但在这种特殊情况下大多很酷。在您编写的“new Add(...)”方法中,包含业务逻辑,然后调用基本的Add(...)方法。

    想让它更酷吗?做一棵树:

    public class Node : List<Node> { }
    

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

答案 4 :(得分:-1)

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

// 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

在现实世界的场景中,它应该谨慎使用,因为它违背了继承原则(应Son允许覆盖他的Dad - 答案取决于你是儿子还是爸爸,但在一个完美的世界里,它不应该是。)

答案 5 :(得分:-1)

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

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方法标记为 new ,以区别于Company X的Bar。虽然他们奇怪地拥有相同的名字,但两者和平共存。他们现有的代码将按预期调用他们的Bar,现有代码将按预期调用您的Bar。

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