なぜIAsyncResultは、BeginInvokedというDelegateへの参照を保持する必要がありますか?IAsyncResult
私のような何か書くことができるようにしたいと思います:
new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete);
void DoSomethingComplete(IAsyncResult ar)
{
ar.EndInvoke();
}
なぜIAsyncResultは、BeginInvokedというDelegateへの参照を保持する必要がありますか?IAsyncResult
私のような何か書くことができるようにしたいと思います:
new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete);
void DoSomethingComplete(IAsyncResult ar)
{
ar.EndInvoke();
}
通常の操作を行うときは、代理人を参照する必要はありません代理人BeginInvoke
; IAsyncResult
をAsyncResult
にキャストし、AsyncDelegate
プロパティからデリゲートを取得できます。そして、誰かが "汚いハックだ"と言う前に、it's documented as being valid at MSDN。
AsyncResultクラスは、代理人を使用して作成された非同期メソッド呼び出しと一緒に使用されます。デリゲートのBeginInvokeメソッドから返されたIAsyncResultは、AsyncResultにキャストできます。 AsyncResultには、非同期呼び出しが呼び出されたデリゲートオブジェクトを保持するAsyncDelegateプロパティがあります。
だから、あなたが書くことができます:あなたはまだ元のデリゲート(または少なくともの種類を知っている必要がありますか、私はこの制限を回避する方法を発見していない
new GenericDelegate(DoSomething).BeginInvoke(DoSomethingComplete);
void DoSomethingComplete(IAsyncResult ar)
{
((GenericDelegate)((AsyncResult)ar).AsyncDelegate)).EndInvoke();
}
注意。もう一度試していない)。 「ノーマル」と
ここで私は、コンパイラが生成する方法を使用して、デリゲートのインスタンスにBeginInvoke
を意味します。 AsyncResult
にキャストするこの技法は、事前定義されたメソッドを使用する場合、つまり独自のBeginX/EndX
メソッドを宣言するクラスを使用する場合は機能しません。これは、クラスがIO完了ポートをブロックするなど、内部的にもっと巧妙なことを行っている可能性があり、したがって異なるタイプのIAsyncResult
を使用する可能性があるためです。しかし、このシナリオでは、うまくいくでしょう。
たIAsyncResultは非常に...使い古さインタフェースです。非常に多くのシナリオで使用可能なインターフェイスになるためには、実際に使用されるすべてのシナリオに適用可能なプロパティとフィールドが必要です。さもなければ、APIは特定のニーズに自然ではないパラメータを提供するのに苦労しています。
状況の一部だけでは、代理人のためにIAsyncResultが作成されます。 Control.BeginInvokeのような他のシナリオは、デリゲートで始まるものではなく、存在する場合にはインターフェイスプロパティに1つを渡すことができません。
ここでは、IAsyncResultは最小限のアプローチをとり、すべての用途で提供できるプロパティのみを持ちます。
は、私は全体の開始/終了パターンが不必要に複雑見つけるように
class Program {
static void Main(string[] args) {
Action d = delegate {
Console.WriteLine("From the delegate");
};
var e = new ManualResetEvent(false);
d.BeginInvoke(r => {
((Action)r.AsyncState).EndInvoke(r);
e.Set();
}, d);
e.WaitOne();
}
}
、と非同期状態パラメータとしてデリゲートを渡して試してみてください - 私はhad a look at wrapping it up(F#が使用するものに非常に匹敵します)。結果:デリゲート(その他)を保持する必要はもうありません。
+1 - 通常のデリゲートとの作業を簡略化しているかどうかはわかりません(理由は私の回答を参照してください)が、あらかじめ定義されたBeginX/EndXメソッドでもうまく動作することが好きです。クローズFTW! –
"d"をキャプチャするのが簡単です。d.BeginInvoke(r => {d.EndInvoke(r); ...}、null); [上にリンクされたブログポストの通り]。 –