请考虑以下代码:
using System.Threading;
public class BaseClass {
private Timer tmrWork;
public BaseClass() {
// read values from config
tmrWork = new Timer(tmrWork_Tick, null, 1, SomeInterval);
}
private void tmrWork_Tick(object state)
{
DoWork();
}
protected abstract void DoWork();
}
public class ChildClass: BaseClass {
public ChildClass() {
// do a bunch of stuff here
// potentially time consuming
}
protected override void DoWork() {
// do stuff
}
}
这里的意图是这样的:基于配置值,从BaseClass继承的类将在某个点上调用一个名为DoWork的方法。
因为在单独的线程上调用该方法(由于使用了System.Threading.Timer),有时在ChildClass构造函数完成执行之前会调用DoWork。
如何在DoWork被调用之前确保子构造函数已完成? 附:代码在Windows服务中。
答案 0 :(得分:3)
最安全的方法是在构造对象时不初始化计时器,而是提供Enabled
属性或Start()
方法,以在对象完全初始化后显式启动计时器。此属性/方法由创建新对象的代码设置/调用,而不是从构造函数本身内设置。
答案 1 :(得分:1)
我能想到的最简单的
public class BaseClass {
private Timer tmrWork;
protected bool IsReady;
public BaseClass() {
// read values from config
tmrWork = new Timer(tmrWork_Tick, null, 1, SomeInterval);
}
private void tmrWork_Tick(object state)
{
if (IsReady)
DoWork();
}
protected abstract void DoWork();
}
public class ChildClass: BaseClass {
public ChildClass() {
// do a bunch of stuff here
// potentially time consuming
IsReady = true;
}
protected override void DoWork() {
// do stuff
}
}
或者更好地制作IsReady抽象方法,以便孩子们必须实现它。在上面的解决方案中(以及Daniel的答案),子类总是有可能忘记设置标志(调用Initialize)
但我觉得你的设计可能有问题。我不认为Timer应该包含在BaseClass中。这样你就可以拥有
new ChildClass();
现在突然有些线程在后台做了一些工作。 对我而言,Timer似乎是某种基础架构代码,它运行在不同类中实现的作业,因此应该从BaseClass中提取。目前的解决方案也是不可测试的。
但当然我可能错了,因为我不知道真正的代码在做什么。
答案 2 :(得分:0)
构造函数的执行顺序与初始化程序的执行顺序相反,因此我会在初始化程序中进行设置。
public class BaseClass {
private Timer tmrWork;
public BaseClass() {
// read values from config
tmrWork = new Timer(tmrWork_Tick, null, 1, SomeInterval);
lock (syncObject)
Init();
}
protected abstract void Init();
private void tmrWork_Tick(object state)
{
lock (syncObject)
DoWork();
}
protected abstract void DoWork();
}
public class ChildClass: BaseClass {
private object syncObject = new object();
protected override void Init() {
lock (syncObject) {
// do a bunch of stuff here
// potentially time consuming
}
}
protected override void DoWork() {
// do stuff
}
}