我有以下代码片段在VS2008中生成“如果隐藏意图使用新关键字”警告:
public double Foo(double param)
{
return base.Foo(param);
}
基类中的Foo()
函数受到保护,我想将它暴露给单元测试,方法是将它放在包装类中,仅用于单元测试。即包装类不会用于其他任何东西。所以我有一个问题是:这是一种公认的做法吗?
返回new
警告。 为什么我必须在这种情况下更新覆盖功能?
答案 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}}
这几乎是避免这种警告的唯一技巧,因为编译器建议你在不知道自己在做什么的情况下隐藏起来。