Delegateを非同期で実行するには,
BeginInvoke EndInvoke
メソッドを利用しますが、その際にBeginInvokeから取得できるのが
IAsyncResult型のオブジェクトになります。
このIAsyncResult型のオブジェクトですが、実態は以下のクラスのインスタンスです。
System.Runtime.Remoting.Messaging.AsyncResult
こちらのクラスにキャストすると、IAsyncResult型のままでは見えない以下のプロパティに
アクセスできます。
- AsyncDelegate
- BeginInvokeの呼び出し元のDelegateが取得できます。
このDelegateが取れると、わざわざ以下のようにしてBeginInvokeを呼ぶ必要がなくなります。
MethodInvoker invoker = new MethodInvoker( ( ) => { Thread.Sleep(TimeSpan.FromSeconds(3)); Console.WriteLine("hoge");}); invoker.BeginInvoke(CallbackMethod, invoker);
よく上記のようにして、AsyncStateに呼び出し元のDelegateを渡しているのを
ちょくちょく見ますが、それはコールバック側で呼び出し元のDelegateのEndInvokeを呼ぶ必要が
あるからです。で、IAsyncResult型では、そのプロパティがないので上記のように渡す必要があります。
void CallbackMethod(IAsyncResult ar){ MethodInvoker invoker = ar.AsyncState as MethodInvoker; invoker.EndInvoker(ar); }
AsyncResultにキャストすれば、直接取得できます。
void CallbackMethod(IAsyncResult ar){ AsyncResult result = ar as AsyncResult; MethodInvoker invoker = result.AsyncDelegate as MethodInvoker; invoker.EndInvoke(result); }
その他にも、AsyncResultには既にEndInvokeが呼ばれたかどうかを判定する
EndInvokeCalled
というプロパティもあります。
以下、サンプル.
#region AsyncResultSamples-01 public class AsyncResultSamples01 : IExecutable{ AutoResetEvent _are = new AutoResetEvent(false); public void Execute(){ Func<DateTime, string> func = CallerMethod; IAsyncResult result = func.BeginInvoke(DateTime.Now, CallbackMethod, _are); _are.WaitOne(); } string CallerMethod(DateTime d){ return d.ToString("yyyy/MM/dd HH:mm:ss"); } void CallbackMethod(IAsyncResult ar){ AsyncResult result = ar as AsyncResult; Func<DateTime, string> caller = result.AsyncDelegate as Func<DateTime, string>; EventWaitHandle handle = result.AsyncState as EventWaitHandle; if(!result.EndInvokeCalled){ Console.WriteLine(caller.EndInvoke(result)); handle.Set(); } } } #endregion
上のサンプルで、わざわざIAsyncResult.AsyncWaitHandleを使っていないのは
AsyncWaitHandleの方は非同期処理自体(ここではCallerMethod)の処理が完了すると
シグナル状態となるのでそのままだとコールバックが呼ばれる前にメイン処理が終わってしまうからです。
AsyncWaitHandleはあくまで非同期処理自体に対して待機処理を行う際に利用します。
今回、サンプルなのでわざとコールバックが終了するまで待機してます。
================================
過去の記事については、以下のページからご参照下さい。
- いろいろ備忘録日記まとめ
サンプルコードは、以下の場所で公開しています。
- いろいろ備忘録日記サンプルソース置き場