0

そのため、バックグラウンドで実行されるライブラリに束またはマルチスレッド コードを書いています。そのため、SynchronizationContext オブジェクトで UI パスを使用しているため、イベントをメインの UI スレッドに戻すことができます。

多くの異なるオブジェクトには、UI がサブスクライブできるパブリック イベントがあります。最初に、ライブラリを初期化するような作成呼び出しに SyncContext オブジェクトをパラメーターとして追加するだけです。渡されたら、それを静的クラスの静的変数に格納して、グローバルにアクセスできるようにします (内部ですが)。

UIスレッドでコードを実行する必要があるときはいつでも、多くのコードを変更せずに簡単に実行できるため、これが気に入っています. しかし、それは私のコードの多くが明示的ではない Static クラスに依存していることを意味します。依存関係を明示的にすると、変数を使用するクラスのコンストラクターに依存関係を追加し、それを必要とするオブジェクトを作成するクラスに参照を格納するために、多くのコード変更が必要になります。

だから私にはオプションがあります

A) SynchronizationContext の依存関係を隠す静的変数

B) ほぼすべてのクラスが、私の SynchronizationContext を認識し、受け渡します。

このような状況に適した別のパターンはありますか?

.net フレームワーク 3.5。メインの UI は WPF になる予定ですが、winform でも動作するようにしたいと考えています。

4

1 に答える 1

1

ライブラリが単一の同期コンテキストからのみ使用されることがわかっている場合、静的メンバーを使用して同期コンテキストをキャプチャできない理由はわかりません (オプション A)。

この依存関係を「明示的」にする必要があるのはなぜですか?

オプション A が問題になる可能性があるのは、ライブラリが複数の同期コンテキストから同時に使用される可能性がある場合です。(たとえば、独自のスレッドとメッセージ ポンプで実行される複数の UI ウィンドウ)。ただし、これはかなり珍しいことです。ほとんどの場合、単一の UI スレッドと単一の同期コンテキストがあります。

また、アプリケーションが (同期コンテキストを介して) UI スレッドへのシリアル化を強制せずにいくつかのイベントを処理したい場合、それはできません。

これらの問題がライブラリの問題でない場合は、オプション A が有効です。

編集 - コメントへの応答:

ジョエル、あなたが説明したことを考えるとこれが役立つかどうかはわかりませんが、明示的な同期コンテキストを使用したい場合に考慮すべきことの 1 つは、作成する必要なくパラメーターを格納するためにスレッドローカル ストレージを使用することですパラメータを取るメソッドのオーバーライド。

たとえば、私は過去に、API の呼び出し元が現在の呼び出しスレッドの既定の同期コンテキストを使用できるようにするだけでなく、別の同期コンテキストを明示的に設定できるようにする必要がありました。私が取ることができた 1 つのアプローチは、同期コンテキスト パラメーターを渡すことができる API メソッドのオーバーロードを提供することでした。私の場合、これは非常に醜いものでした。かなりまれなユース ケースに対して多数のメソッド オーバーロードを作成する必要があったからです。

そのため、代わりに、現在の同期コンテキストがオーバーライドされる「スコープ」の作成を処理するクラスを作成しました (それにより、呼び出されたメソッドに効果的に渡します)。このクラスは、(順番に) 1) 現在の同期コンテキストのキャッシュ、2) 呼び出し元によって指定された同期コンテキストへの現在のコンテキストの設定、および 3) 'スコープ' の最後での同期コンテキストのリセットを処理します。

外観は次のとおりです。

public class SyncContextScope : IDisposable
{
    SynchronizationContext m_contextOnEntry;

    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="useContext"></param>
    public SyncContextScope(SynchronizationContext useContext)
    {
        m_contextOnEntry = SynchronizationContext.Current;
        SynchronizationContext.SetSynchronizationContext(useContext);
    }

    #region IDisposable Members

    void IDisposable.Dispose()
    {
        SynchronizationContext.SetSynchronizationContext(m_contextOnEntry);
    }

    #endregion
}

そして、あなたはそれを次のように使います:

using(new SyncContextScope(yourSyncContext))
{
   yourApi.CallSomeMethod();
}

API のメソッド (上記の例の CallSomeMethod) は、SynchronizationContext.Current (TLS を使用して同期コンテキストを保存する) を利用できるようになりました。synchronizationcontext パラメータを提供する必要はありません。

于 2009-12-28T17:12:30.107 に答える