1

考虑以下代码:

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 之前,如何确保子构造函数已完成?
PS 代码位于 Windows 服务中。

4

3 回答 3

3

最安全的方法是在构造对象时不初始化计时器,而是在对象完全初始化后提供一个Enabled属性或方法来显式启动计时器。Start()此属性/方法由创建新对象的代码设置/调用,而不是从构造函数本身内部。

于 2013-11-03T22:57:32.110 回答
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 抽象方法,以便孩子们必须实现它。在上面的解决方案(和丹尼尔的回答)中,子类总是有可能忘记设置标志(调用初始化)

但我真的认为你的设计可能有问题。我认为 Timer 不应该包含在 BaseClass 中。这样你就可以拥有

new ChildClass();

现在突然有些线程在后台做了一些工作。在我看来,Timer 是一种运行在不同类中实现的作业的基础设施代码,因此应该从 BaseClass 中提取。当前的解决方案也是不可测试的。

但当然我可能错了,因为我不知道真正的代码在做什么。

于 2013-11-03T20:08:29.660 回答
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
    }
}
于 2013-11-03T20:12:01.040 回答