如何确保在构造函数完成执行之前不会调用任何内容

时间:2013-11-03 20:01:37

标签: c#

请考虑以下代码:

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服务中。

3 个答案:

答案 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
    }
}