4

BeginInvoke/EndInvoke パターンを使用して非同期メソッドの実装を記述する場合、コードは次のようになります (これがキャッシュの非同期ラッパーであると推測しなくても済むようにするためです)。

IAsyncResult BeginPut(string key, object value)
{
    Action<string, object> put = this.cache.Put;
    return put.BeginInvoke(key, value, null, null);
}

void EndPut(IAsyncResult asyncResult)
{
    var put = (Action<string, object>)((AsyncResult)asyncResult).AsyncDelegate;
    put.EndInvoke(asyncResult);
}

デリゲートの型がわかっているため、キャストできるため、これは完全にうまく機能します。Putただし、メソッドが void を返しますが、呼び出しを終了するには、メソッドを強く型付けされたデリゲートにキャストする必要があるように見えるため、2 つのメソッドがあると面倒になり始めます。

IAsyncResult BeginPut(string key, object value)
{
    Action<string, object> put = this.cache.Put;
    return put.BeginInvoke(key, value, null, null);
}

IAsyncResult BeginPut(string region, string key, object value)
{
    Action<string, string, object> put = this.cache.Put;
    return put.BeginInvoke(region, key, value, null, null);
}

void EndPut(IAsyncResult asyncResult)
{
    var put = ((AsyncResult)asyncResult).AsyncDelegate;

    var put1 = put as Action<string, object>;
    if (put1 != null) 
    {
        put1.EndInvoke(asyncResult);
        return;
    }

    var put2 = put as Action<string, string, object>;
    if (put2 != null) 
    {
        put2.EndInvoke(asyncResult);
        return;
    }

    throw new ArgumentException("Invalid async result", "asyncResult");
}

デリゲートについて気にするのは戻り値の型 (この場合は void) だけであり、提供された引数ではないため、これを行うためのよりクリーンな方法があることを願っています。しかし、私は頭を悩ませ、オフィスの他の人に尋ねましたが、誰も答えを思いつくことができません.

1 つの解決策が custom を作成することであることはわかっていますが、これIAsyncResultは の遅延インスタンス化などの潜在的なスレッド化の問題を伴う非常に難しい作業であり、WaitHandleそのルートをたどるよりも、この少しハックなコードを使用したいと考えています。

isチェックのカスケード セットなしで呼び出しを終了する方法についてのアイデアはありますか?

4

3 に答える 3

4

私は間違っていました。よりクリーンな方法があります。

Action( IAsyncResult )デリゲートの特定の型が既にわかっている同じコンテキストで、特定のメソッドのデリゲートを作成EndInvoke()し、それを AsyncState として渡します。EndPut()便宜上、コールバックとして渡します。

IAsyncResult BeginPut( string key, object value ) {
    Action<string, object> put = this.Put;
    return put.BeginInvoke( key, value, EndPut,
        new Action<IAsyncResult>( put.EndInvoke ) );
}

IAsyncResult BeginPut( string region, string key, object value ) {
    Action<string, string, object> put = this.Put;
    return put.BeginInvoke( region, key, value, EndPut,
        new Action<IAsyncResult>( put.EndInvoke ) );
}

そして、あなたはそれを終わらせます。

void EndPut( IAsyncResult asyncResult ) {
    var del = asyncResult.AsyncState as Action<IAsyncResult>;
    del( asyncResult );
}
于 2008-10-09T21:42:08.603 に答える
0

より一般的な過負荷に戻るだけで、問題を回避してみませんか。

IAsyncResult BeginPut(string key, object value) {
   return this.BeginPut(null, key, value);
}

IAsyncResult BeginPut(string region, string key, object value) {
   Action<string, string, object> put = this.Put;
   return put.BeginInvoke(region, key, value, null, null);
}

void EndPut(IAsyncResult asyncResult) {
   var put = (Action<string, string, object>)((AsyncResult)asyncResult).AsyncDelegate;
   put.EndInvoke(asyncResult);
}
于 2008-10-09T21:22:04.353 に答える
0

編集:私の他の答えを見てください。それはよりきれいにすることができます。

これをきれいにする方法はないと思います。EndPut同じメソッドを使用して複数のタイプの非同期呼び出しを終了することで、基本的にこれを避けられませんでした。(callback と asyncstate)の最後の 2 つのパラメーターとしてEndPutとデリゲートを渡すことで、通常のパターンに従うこともできますが、 call の順序でデリゲートの型をテストする必要があります。putBeginInvoke()EndInvoke()

それらをキャストしてDelegateもまったく役に立ちません。

私はマーク・ブラケットのアイデアが好きです。これらのオプションに帰着すると思います:

  • 1 つのオーバーロードが別のオーバーロードを呼び出すようにすることで、それらを完全に結合します。1 つのデリゲート、1 つのコールバック。
  • を呼び出すための 2 つのコールバックを用意して、それらを完全に分離しますEndInvoke()

それらを除いて、唯一のことは、コードを少しきれいにして、switchまたは を使用してルックアップ辞書を使用し、デリゲートをその状態オブジェクトとしてasyncResult.AsyncState.GetType()渡すことです。put

于 2008-10-09T21:31:37.593 に答える