在C#中,new
修饰符可用于隐藏基类方法而不覆盖基类方法。
我从未遇到过隐藏方法是最佳选择的情况。是否存在方法隐藏是最佳选择的情况?
答案 0 :(得分:19)
使用方法隐藏的原因很少但非常好。 Eric Lippert posted a great example在他的博客上:
interface IEnumerable<T> : IEnumerable {
new IEnumerator<T> GetEnumerator();
}
但是,我认为隐藏应该是例外,并且只是谨慎使用。
答案 1 :(得分:16)
为了方便呼叫者,我倾向于使用它,例如:
abstract public class Animal { }
public class Mouse : Animal { }
public class AnimalTrap
{
public Animal TrappedAnimal { get; }
}
public class MouseTrap : AnimalTrap
{
new public Mouse TrappedAnimal
{
get { return (Mouse)base.TrappedAnimal; }
}
}
因此,当派生类保证被困动物永远是鼠标时,调用者不必自己强制转换为Mouse
。并且多态功能保持不变。
答案 2 :(得分:14)
当您创建自定义控件并希望阻止某些属性出现在设计器中时,这通常是一个不错的选择。有时属性不会被覆盖,但设计者并不关心它,它只关心最低级别的公共属性是否具有[Browsable]
属性。
例如,假设您的控件不支持填充。 Control.Padding属性不可覆盖。但是你也知道,如果有人设置了填充,那么 bad 就不会发生,只是该属性不会做任何东西,所以你不希望你的用户在设计师中看到它并认为它确实有效。所以,隐藏它:
public class MyControl : Control
{
[Browsable(false)]
public new Padding Padding
{
get { return base.Padding; }
set { base.Padding = value; }
}
}
在这种情况下,我们字面上使用成员隐藏隐藏成员 - 来自设计师。
顺便说一句,我知道还有其他方法可以实现这一目标 - 这只是一种可能的选择。
答案 3 :(得分:6)
我能想到的最常见的例子是DbCommand
vs SqlCommand
;具体类型(SqlCommand
等)通常会执行大量隐藏方法,以使返回类型的属性/方法显示正确的实现类型。这是因为相关对象本身具有其他(特定于实现的)功能,并且调用者不希望每次调用时都必须进行转换。
答案 4 :(得分:4)
是的,例如,如果您只是基类的使用者并且发布了新版本的基类,那么突然间该方法的签名与您已经实现的方法之一具有完全相同的签名在派生类中,您需要能够隐藏基类方法,并使用new
清楚地表明您正在隐藏基类方法...
答案 5 :(得分:1)
我不得不求助于方法隐藏一次。我使用的是第三方库,它提供了一种非虚拟的方法(这是整个事情的关键)。这是一个分配事物实例的方法。但我需要扩展该方法的功能。
所以我使用了新的&#39;用于隐藏基类实现的关键字,并在派生类中提供自己的实现。这并不意味着我没有调用基类方法。事实上我确实调用了基类方法,但我也在我的方法中做了其他的东西,最后一切都很顺利。
所以我说原因如下:
我的2美分......
答案 6 :(得分:1)
我最近遇到了一个新的&#39;关键字非常有用。我正在为遗留代码库中的方法编写单元测试,并且我正在编写测试的类中的一些方法将隐藏在方法中的外部依赖项。包含一个解决问题的模拟框架在当时似乎是不必要的,所以我没有使用模拟框架,而是继承了我想在单元测试类中测试的类。但是,父方法不是虚拟的,因此无法覆盖。我的第一个解决方案是简单地将virtual关键字添加到原始方法中以允许它被覆盖并且测试工作得很好。即使它有效,我也不认为只是因为需要&#34; mock&#34;才能将虚拟关键字添加到方法签名中。它在单元测试中是一个很好的设计决策(但我可能错了)。而是使用&#39; new&#39;子类中的关键字使我能够摆脱&#39;父方法依赖项通过使用具有静态返回值的方法隐藏原始方法,从而为其余方法编写快速单元测试以及将非虚方法更改为虚方法时。
一般来说,我不确定这种技术是否可以被视为良好做法。但是,在编写测试套件时,使用这种技术可能非常有用,以便在处理具有许多依赖项的遗留代码时轻松进行重构,并且没有自动化的测试套件。重构工作完成后,测试很可能会得到改善。
编辑:因为方法隐藏只发生在私有继承类中,所以不应该引起其他用例中可能出现的混淆。
答案 7 :(得分:0)
有一次我使用它是在自定义winforms控件中。我的自定义控件会覆盖Text
属性,我想在事件发生变化时引发它。基础Control
类附带TextChanged
事件,但基本事件上有属性,以防止它出现在intellisense中的设计器或中。由于我们在自定义控件中使用该事件,因此这是不可取的,因此我们执行以下操作:
[Browsable(true)]
[EditorBrowsable(EditorBrowsableState.Always)]
public new event EventHandler TextChanged
{
add { base.TextChanged += value; }
remove { base.TextChanged -= value; }
}
无论用于访问它的引用类型如何,事件处理程序仍将添加到同一事件中,但派生类型的引用将在intellisense中显示TextChanged
事件,并且当我们的控件时放置在设计器中的表单上,TextChanged
事件将显示在属性窗口中。