每当我覆盖基类的方法时,除了我执行此方法之外,我似乎有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();
}
}
我的问题是,子类如何知道(不看基类实现)父类所期望的顺序(或选项)? 有没有一种方法可以让父类强制执行所有派生类的三个替换中的一个?
答案 0 :(得分:39)
子类如何知道(不看基类实现)父类所期望的顺序(或选项)?
当您进行子类化和重写方法时,无法“知道”这一点。正确的文档确实是唯一的选择。
有没有一种方法可以让父类强制执行所有派生类的三个替换中的一个?
这里唯一的选择是避免这个问题。可以将其声明为非虚拟,而不是允许子类覆盖该方法,并在适当的位置调用虚方法。例如,如果要强制执行该子类“首先调用您的版本”,您可以执行以下操作:
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 :(得分:2)
这就是为什么我觉得虚拟方法在库中发货时会很危险。事实是,如果不看基类,你就不会真正知道,有时候你必须启动reflektor,阅读文档或者通过反复试验来处理它。
在自己编写代码时,我总是厌倦遵循以下规则:
不需要覆盖受保护虚拟方法的派生类来调用基类实现。即使未调用其实现,基类也必须继续正常工作。
这取自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上进行基本调用。
所以,无论长短,它都会有所不同,不幸的是,没有即时的认识方式。如果我有疑问,我最初会省略这个电话。
答案 2 :(得分:1)
简短的回答是否定的。您不能强制执行子调用基本方法的顺序,或者根本不调用它。
从技术上讲,此信息应包含在基础对象的文档中。如果你必须在子类代码之前或之后运行一些代码,那么你可以执行以下操作:
1)在基类中创建非虚函数。我们称之为MyFunction
2)在基类中创建受保护的虚拟函数。我们称之为_MyFunction
3)派生类扩展了_MyFunction方法。
4)让MyFunction调用_MyFunction并在调用它之前或之后运行它需要运行的代码。
这种方法很难看,需要很多额外的代码,所以我建议你只在文档中加注一下。
答案 3 :(得分:0)
库类设计者应记录基类的要求。 这个问题是一些库主要包含密封类的原因。