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 に答える