如何“正确”重写基类方法?
每当我重写一个基类的方法,除了我的这个方法的实现,我似乎有3个选择。如何“正确”重写基类方法?
1)调用base.Method(),然后提供我的实现。
2)提供我的实现,然后调用base.Method()
3)只需提供我的实现。
最近在使用库时,我已经意识到由于没有实现库所期望的方法而引入的一些错误。我不确定图书馆是否有问题,或者我的理解有问题。
我将举一个例子。
public class ViewManager {
public virtual void Customize(){
PrepareBaseView();
}
}
public class PostViewManager {
public override void Customize(){
base.Customize();
PreparePostView();
}
}
public class PreViewManager {
public override void Customize(){
PreparePreView();
base.Customize();
}
}
public class CustomViewManager {
public override void Customize(){
PrepareCustomView();
}
}
我的问题在这里怎么可能一个子类知道(不考虑看看基类实现)的顺序(或期权)是由父类的预期? 有没有一种方法可以让父类强制三个交替之一到所有的派生类?
子类如何知道(无需查看基类实现)父类预期的顺序(或选项)?
当你继承和重写方法时,没有办法“知道”这个。正确的文档是这里唯一的选择。
有没有一种方法,其中父类可以强制三个交替之一到所有的派生类?
这里唯一的选择是避免这个问题。而不是让子类覆盖的方法,它可以声明非虚,并呼吁在适当的地方虚方法。例如,如果要强制执行的子类“先打电话给你的版本”,你可以这样做:
public class BaseClass {
public void Method() // Non-virtual
{
// Do required work
// Call virtual method now...
this.OnMethod();
}
protected virtual void OnMethod()
{ // Do nothing
}
}
子类就可以“覆盖” OnMethod,并提供售后服务“方法”的工作出现这种情况的功能。
这是必需的原因是虚拟方法的设计允许子类完全替代父类的实现。这是有目的地完成的。如果您想防止这种情况,最好使该方法非虚拟化。
你打败了我。这是脆弱的基类**问题。解决方法为+1(您也击败了我:),**模板方法模式**。您甚至可以创建受保护的'OnMethod'抽象,以便派生类知道它们*具有*提供它们自己的实现,而且它们不必调用基本实现(假设它没有意义实例化'Base')。 – shambulator 2010-06-30 20:18:12
+1这可以帮助您避免开发人员的冲突。 – Marc 2010-06-30 20:23:18
@shambulator - Override是可选的,所以它可能无法与'OnMethod'抽象相提并论。它仍然是一个不错的选择,虽然 – 2010-06-30 20:24:42
简短的回答是否定的。你不能以孩子调用基本方法的顺序执行,或者根本不调用它。
从技术上讲,这些信息应该包含在基础对象的文档中。如果您绝对必须在子类的代码之前或之后运行一些代码,则可以执行以下操作:
1)在基类中创建一个非虚函数。我们称之为MyFunction
2)在基类中创建一个受保护的虚函数。我们称之为_MyFunction
3)派生类扩展了_MyFunction方法。
4)让MyFunction调用_MyFunction并在调用它之前或之后运行它需要运行的代码。
这种方法是丑陋的,将需要大量的额外的代码,所以我建议只是把通知的文件中。
我不知道像PostSharp这样的东西是否可以强制执行该命令。 – FrustratedWithFormsDesigner 2010-06-30 20:14:48
基本类的需求应该由库设计者记录。 这个问题就是为什么一些库包含主要密封类的原因。
这就是为什么我觉得虚拟方法是危险的,当你把它们放在图书馆。事实是,如果不查看基类,你永远不会知道,有时你必须启动反射器,阅读文档或通过反复试验来处理它。
在编写代码时我自己,我一直累到遵循说规则:
重写受保护的虚方法派生类不需要调用基类的实现。即使未调用其实现,基类也必须继续正常工作。
这取自http://msdn.microsoft.com/en-us/library/ms229011.aspx,但是这是用于事件设计,但我相信我在框架设计指南书(http://www.amazon.com/Framework-Design-Guidelines-Conventions-Libraries/dp/0321246756)中阅读了此内容。
但是,这显然是不正确的,例如,ASP.NET Web窗体需要在Page_Load上进行基址调用。
所以,总之,它会变化,不幸的是没有即时的知道方式。如果我有疑问,我会最初省略电话。
多么美妙的答案。我的确切想法。上投票。 – Xtro 2017-11-25 23:32:24
'PostViewManager','PreViewManager','CustomViewManager'继承自'ViewManager'?如果是这样,你应该编辑代码。 – LaTeX 2011-02-16 05:53:42