55

我有以下代码片段在 VS2008 中生成“如果有意隐藏则使用新关键字”警告:

public double Foo(double param)
{
   return base.Foo(param);
}

基类中的Foo()函数受到保护,我想通过将其放入包装类中来将其公开给单元测试,仅用于单元测试的目的。即包装类不会用于其他任何事情。所以我有一个问题是:这是公认的做法吗?

回到new警告。为什么在这种情况下我必须新的覆盖功能?

4

4 回答 4

69

new只是清楚地表明您知道您正在踩踏现有的方法。由于现有的代码是protected,这没什么大不了的 - 您可以安全地添加new以停止它的呻吟。

当您的方法做了不同的事情时,差异就会出现。任何引用派生类和调用的变量Foo()都会做一些不同的事情(即使是同一个对象)作为引用类和调用的变量Foo()

SomeDerived obj = new SomeDerived();
obj.Foo(); // runs the new code
SomeBase objBase = obj; // still the same object
objBase.Foo(); // runs the old code

这显然会对任何知道SomeDerived和调用的现有代码产生影响Foo()——即它现在正在运行一个完全不同的方法。

另外,请注意,您可以标记它protected internal,并使用它[InternalsVisibleTo]来提供对单元测试的访问(这是最常见的用法[InternalsVisibleTo];然后您的单元测试可以直接访问它而无需派​​生类。

于 2009-01-16T16:35:53.517 回答
40

关键是您没有覆盖该方法。你在隐藏它。如果您要覆盖它,则需要override关键字(此时,除非它是虚拟的,否则编译器会抱怨,因为您无法覆盖非虚拟方法)。

您使用new关键字告诉编译器和任何阅读代码的人,“没关系,我知道这只是隐藏基本方法而不是覆盖它 - 这就是我的意思。”

坦率地说,我认为隐藏方法很少是一个好主意——我会使用不同的方法名称,就像 Craig 建议的那样——但这是一个不同的讨论。

于 2009-01-16T16:38:59.173 回答
8

您正在更改没有名称的可见性。调用您的函数 TestFoo ,它将起作用。是的,恕我直言,因此可以接受子类化。

于 2009-01-16T16:36:22.360 回答
1

您总是会发现一些棘手的情况,其中new关键字可以用于隐藏,而大多数情况下可以避免。

然而,最近我真的需要这个关键字,主要是因为该语言缺少一些其他适当的语法功能来完成现有的访问器,例如:

如果您考虑一个老式的课程,例如:

KeyedCollection<TKey, TItem>

您会注意到通过索引访问项目的访问器是:

TItem this[Int32 index] { get; set; }

两者都有{ get; set; },它们当然是强制性的,因为继承了ICollection<T>and Collection<T>,但是只有一个{ get; }可以通过它们的键访问项目(我对这个设计有一些猜测,有很多原因,所以请注意我选择了仅用于说明KeyedCollection<TKey, TItem>)目的)。

无论如何,密钥访问只有一个吸气剂:

TItem this[TKey key] { get; }

但是如果我想添加{ set; }支持呢,从技术上讲,它并不是那么愚蠢,特别是如果你继续从以前的属性定义中推理,它只是一种方法......唯一的方法是显式地实现另一个虚拟接口但是当你想要隐含你必须想出new关键字,我隐藏了访问器定义,保留了 get; 基本定义,只需添加一组塞满一些个人物品的集合即可使其正常工作。

我认为对于这个非常具体的场景,这个关键字是完全适用的,特别是在没有带入{ get; }部分的上下文中。

  public new TItem this[TKey key]
  { 
      get { return base... }
      set { ... }
  }

这几乎是避免这种警告的唯一技巧,因为编译器会建议您可能在没有意识到自己在做什么的情况下隐藏。

于 2014-07-24T06:07:32.160 回答