你为什么要掩饰一个基类成员?

时间:2010-08-31 14:43:55

标签: c# class encapsulation mask

我刚刚学会了如何屏蔽基类成员(使用new),但我忽略了为什么我想这样做。屏蔽是否为我们提供了一定程度的保护,就像使用封装一样?请指教。

6 个答案:

答案 0 :(得分:3)

它不仅仅用于遮蔽。它实际上打破了继承链,因此如果调用基类方法,则不会调用派生类中的方法(只是基类中的方法)。

您实际上是在创建一个与基类方法无关的 new 方法。因此,“新”关键字。

如果要定义一个与基本类型方法具有相同签名但具有不同返回类型的方法,则可以使用“new”关键字。

答案 1 :(得分:3)

您很少使用“new”来掩​​盖基类成员。

它主要用于派生类首先拥有成员的情况,然后将其添加到基类---用于不同目的的相同名称。 new即表示您承认您知道自己使用的方式不同。在C ++中添加基本成员时,它只是将现有方法静默地合并到继承链中。在C#中,您必须在newoverride之间进行选择,以向您显示正在发生的事情。

答案 2 :(得分:3)

我遇到的 有效 安全示例更具体的是返回类型或在属性上提供set访问器。我不是说那些是唯一的,但这就是我发现的全部。

例如,假设您有一个非常简单的基础,如下所示:

public abstract class Base
{
  public string Name { get; protected set; }

  public Base(string name)
  { Name = name; }
}

你可以得到一个看起来更像这样的派生词:

public class Derived : Base
{
  public new string Name 
  {
    get { return base.Name; }
    set { base.Name = value; }
  }

  public Derived(string name) : base(name)
  { }         
}

假设业务规则允许这个特定的Derived具有可更改的名称,我相信这是可以接受的。 new的问题在于它根据实例的查看类型更改行为。例如,如果我要说:

Derived d = new Derived("Foo");
d.Name = "Bar";
Base b = d;
b.Name = "Baz"; // <-- No set available.

在这个琐碎的例子中,我们没事。我们用new覆盖了这种行为,但并没有突破。改变回报类型需要更多技巧。也就是说,如果使用new更改派生类型的返回类型,则不应允许基类设置该类型。看看这个例子:

public class Base
{
  public Base(Base child)
  { Child = child; }

  public Base Child { get; private set; }
}

public class Derived
{
 public Derived(Derived child) : base(child)
 {  }

 public new Derived Child 
 { get { return (Derived)base.Child; } }

}

如果我可以set ChildBase,我可能会在Derived课程中遇到投射问题。另一个例子:

Derived d = new Derived(someDerivedInstance);
Base b = d;
var c = b.Child;  // c is of type Base
var e = d.Child;  // e is of type Derived

我不能通过将所有Derived类视为基础来破坏任何业务规则,只是不方便键入check和cast。

答案 3 :(得分:3)

  

我刚学会了如何屏蔽基类成员(使用new)

仅供参考,此功能通常称为“隐藏”而非“屏蔽”。我认为“屏蔽”是位数组中的清除位。

  

我错过了为什么我想这样做的观点。

通常你不想。出于某些原因使用而不使用此功能,请参阅我在2008年关于此主题的文章:

http://blogs.msdn.com/b/ericlippert/archive/2008/05/21/method-hiding-apologia.aspx

  

屏蔽是否为我们提供了一定程度的保护,就像使用封装一样?

不,它没有。

答案 4 :(得分:1)

您所指的是Name Hiding。这主要是一个方便的功能。如果从使用new无法控制源的类继承,即使未将其声明为虚拟(或完全更改签名,如果它是虚拟的),也可以更改方法的行为。 new关键字只是抑制编译器警告。您基本上是告知编译器您有意将该方法隐藏在父类中。

由于同样的原因,Delphi拥有reintroduce关键字。

除了被禁止的警告之外,这会给你带来什么?不是很多。您无法从父类访问new方法。如果您的子类直接实现接口(可以从其父类继承它),则可以从接口访问它。您仍然可以从子级调用父类的成员。您的类的任何其他后代将继承new成员而不是父成员。

答案 5 :(得分:0)

这实际上称为成员隐藏。有几种常见的情况可以适当使用。

  • 它允许您解决版本问题,其中基类或派生类作者无意中创建了与现有标识符冲突的成员名称。
  • 它可用于模拟返回类型的协方差。

关于第一点......基类的作者可能稍后在派生类中添加与现有成员同名的成员。基类作者可能不了解派生类,因此不期望她应该避免名称冲突。 C#使用隐藏机制支持类层次结构的独立演化。

关于第二点......您可能希望一个类实现一个指定某个方法签名的接口,因此只有在您将该类型子类化时才会被锁定为返回某个类型的实例非常希望呼叫者能够看到具体的类型。考虑这个例子。

public interface IFoo { }

public class ConcreteFoo { }

public abstract class Base
{
  private IFoo m_Foo;

  public Base(IFoo x) { m_Foo = x; }

  public IFoo Foo { get { return m_Foo; } }
}

public class Derived
{
  public Derived(ConcreteFoo x) : base(x) { }

  public new ConcreteFoo Foo { get { return (ConcreteFoo)base.Foo; } }
}