4

システム状態が変化したときに他のコントロールやコードに通知するために、アプリケーション用の単純な静的クラスのステート マシンを作成しようとしています。そして、私はほとんどそれを持っていると思いますが、回避方法がわからないという小さな問題に遭遇しています。

コードは次のとおりです。

// An enum denoting the 3 States
public enum Status { Error = -1, Working, Ready }

// The main state change class
public static class Sys
{
    // system status
    private static Status state;

    // delegate and event
    public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);
    public static event StateChangeHandler OnStateChange;

    public static Status State
    {
        get { return state; }
        set
        {
            SysInfoEventArgs sysInfo = new SysInfoEventArgs(state, value);
            state = value;
            OnStateChange(this, sysInfo);
        }
    }
}

/// <summary>Contains previous and current state info</summary>
public class SysInfoEventArgs : EventArgs
{
    public readonly Status oldState;
    public readonly Status newState;
    public SysInfoEventArgs(Status oldState, Status newState)
    {
        this.oldState = oldState;
        this.newState = newState;
    }
}

私が抱えている問題は、次の行にあります。

 OnStateChange(this, sysInfo);

具体的には、「これ」という言葉は違法です。そして、その理由を理解しています。「this」は、インスタンス化されたオブジェクト (静的クラスではない) の自己を参照することになっています。

複数のコピーをインスタンス化できるクラスよりも、ステート マシン用の Static クラスを使用したいと考えています。(それほど悪いことではありませんが、静的クラスを持つことでコードがきれいになると思います。)

では、これをどのように機能させるべきですか?

アップデート:

フォローアップとして、問題は私が抱えていた技術的な失敗ではなく、私が取っていたアプローチに関するものだったので、Jon Skeet の答えを正しいものとして選択しました。ただし、以下の他の回答のほとんどすべてが、私が扱っていた技術的な不具合を修正します。

奇妙なことに、私が書いたアプリケーションを同僚とレビューしていたとき、彼女はプログラムがサーバー接続の状態と実行中の作業の状態の両方を追跡する必要があると指摘しました。(はい、バージニア州、これは 2 つのステート マシンが必要であることを意味します。したがって、上記のコードからすべての「静的」キーワードを削除し、通常のクラスにすることが賢明なアプローチでした。)

改めまして、皆様!

4

5 に答える 5

14

なぜ静的クラスが必要なのですか? 非静的クラスの使用を自然に提案するのは、ステートマシンです (状態を持っています)。本当に必要な場合は、その単一のインスタンスを参照する静的変数をいつでも持つことができます。

基本的に、あなたの本能は私の見解では正しくありません。通常のクラスを使用すると、コードが静的なものよりもきれいになります。静的クラスが状態を持つことはめったにありません。おそらく、キャッシュ (疑わしいとはいえ)、または診断目的のカウンターなどです。クラスではなくオブジェクトの観点から考えてみてください。現在の状態が異なり、イベント ハンドラーが異なる 2 つの別個のステート マシンを使用することは理にかなっていますか? 想像するのは簡単です。つまり、テストなどの新しいインスタンスを簡単に作成できるということです (独立したテストを並行して実行することもできます)。したがって、マシンのインスタンスに状態を保持することは自然に適合します。

静的メソッドや静的クラスなどがあってはならないと考える人もます。それは少し先のことだと思いますが、少なくとも静的を導入することによるテスト容易性の影響を常に考慮する必要があります。

于 2010-03-09T19:16:11.190 に答える
6

静的クラスや静的メソッドなどの静的スコープ内で作業している場合、「this」は使用できません。

ここには 2 つのオプションがあります。null「sys」パラメーターを渡すことができます。実際、静的クラスの場合、このパラメーターは実際には役に立ちません。「送信者」は常に静的クラスだからです。

または、状態通知機能をsingletonにすることを検討することもできます。これにより、非静的クラスのインスタンスを 1 つ持つことができます。これには、将来の要件が変更された場合にも、非静的実装への移行が容易になるという 1 つの利点があります。


さらに、このイベントを発生させる前に、サブスクライバーが存在することを確認する必要があります。そうしないと、次のような問題が発生する可能性があります。

public static Status State
{
    get { return state; }
    set
    {
        SysInfoEventArgs sysInfo = new SysInfoEventArgs(state, value);
        state = value;
        var handler = OnStateChange;
        if (handler != null)
            handler(null, sysInfo);
    }
}
于 2010-03-09T19:15:00.490 に答える
1

デリゲートを変更します。

から:

public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);

に:

public static delegate void StateChangeHandler(SysInfoEventArgs sysStateInfo);
于 2010-03-09T19:16:36.353 に答える
1

本当に静的クラスを維持して のセマンティクスを使用したい場合はobject sender、適切に渡すのはtypeof(Sys). これは、(古くて珍しい) 静的クラスのロック イディオムにも似ています。

イベント ハンドラーは決してその値を使用せず、実際nullには同じように機能するためです。

于 2010-03-09T19:27:17.297 に答える
1

私はこのコードを変更します:

public static delegate void StateChangeHandler(object sys, SysInfoEventArgs sysStateInfo);
public static event StateChangeHandler OnStateChange;

に:

public static event Action<SysInfoEventArgs> OnStateChange;
于 2010-03-09T19:20:53.570 に答える