如果打算隐藏,请使用新关键字

时间:2009-01-16 16:32:46

标签: c# inheritance warnings new-operator

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

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

基类中的Foo()函数受到保护,我想将它暴露给单元测试,方法是将它放在包装类中,仅用于单元测试。即包装类不会用于其他任何东西。所以我有一个问题是:这是一种公认​​的做法吗?

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

4 个答案:

答案 0 :(得分:69)

new只是清楚地表明你知道你正在踩踏现有的方法。由于现有代码为protected,因此没有那么大 - 您可以安全地添加new以阻止其呻吟。

当你的方法做了不同的事情时,差异就出现了;引用派生类和调用Foo()的任何变量都会做一些与引用 base 类并调用{{}的变量不同(即使使用相同的对象) 1}}:

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]最常见的用途;然后是您的单元测试可以在没有派生类的情况下直接访问它。

答案 1 :(得分:38)

关键是你重写方法。你在隐藏它。如果你覆盖它,你需要override关键字(此时,除非它是虚拟的,编译器会抱怨,因为你不能覆盖非虚方法)。

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

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

答案 2 :(得分:8)

您正在更改没有名称的可见性。调用你的函数TestFoo,它会工作。是的,恕我直言,由于这个原因,子类是可以接受的。

答案 3 :(得分:1)

您总能找到一些棘手的情况,new关键字可用于隐藏,而大部分时间都可以避免。

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

如果你考虑一个老式的课程:

KeyedCollection<TKey, TItem>

您会注意到,通过索引获取项目的访问者是:

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

由于{ get; set; }ICollection<T>的继承,Collection<T>{ get; }两者当然是强制性的,但只有一个KeyedCollection<TKey, TItem>)用于通过其键获取项目(我对这个设计有一些猜测,并且有很多原因,所以请注意我只是为了插图而选择TItem this[TKey key] { get; } 。)

无论如何,只有一个用于密钥访问的getter:

{ set; }

但是如果我想添加new支持怎么样呢?从技术上来说,这并不是那么愚蠢,特别是如果你继续推理前者对于该属性的定义,它只是一种方法......唯一的方法是明确地实现了另一个虚拟接口,但是当你想要隐式时你必须提出{ get; }关键字,我隐藏了访问器定义,保持了get;基本定义,只需添加一些包含一些个人物品的集合即可使其工作。

我认为对于这个非常具体的情况,这个关键字是完全适用的,特别是对于没有带到 public new TItem this[TKey key] { get { return base... } set { ... } } 部分的上下文。

{{1}}

这几乎是避免这种警告的唯一技巧,因为编译器建议你在不知道自己在做什么的情况下隐藏起来。