これが、非同期プロセスを開始する拡張メソッドを作成する正しい方法であるかどうか、他のユーザーと再確認したいと思います。呼び出されたときに、そのプロセスを本質的に待機して結果を取得する関数を返します。
public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg, Action<IAsyncResult> callback)
{
IAsyncResult result = function.BeginInvoke(arg, new AsyncCallback(callback), function);
return delegate
{
return function.EndInvoke(result);
};
}
基本的には、次のように使用したい (疑似コード):
Func<R> myFunc = (some delegate).HandleInvoke(arg, callback);
// at this point the operation begins, but will be nonblocking
// do other stuff
var result = myFunc(); // now I am deciding to wait on the result, which is blocking
この状況で WaitHandles を待つことを心配する必要があるかどうかはわかりませんでした。また、コールバックを渡す必要があるかどうかもわかりません。また、これは閉鎖を構成すると思いますか?
編集
これに尽きる、
public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg)
{
IAsyncResult asyncResult = function.BeginInvoke(arg, iAsyncResult =>
{
if (!(iAsyncResult as AsyncResult).EndInvokeCalled)
{
(iAsyncResult.AsyncState as Func<T, R>).EndInvoke(iAsyncResult);
}
}, function);
return delegate
{
WaitHandle.WaitAll(new WaitHandle[] { asyncResult.AsyncWaitHandle });
return function.EndInvoke(asyncResult);
};
}
これはうまくいくようです。コールバックは、EndInvoke が呼び出されたかどうかを確認し、呼び出されていない場合はそれを呼び出します。それ以外の場合は、返されたデリゲート内で EndInvoke が呼び出されます。
2回目の編集
これが私の最新の試みです-まだエラーをスローしておらず、うまく処理しているようです。デリゲートが function.EndInvoke() の結果を返した場所で機能させることができませんでしたが、匿名コールバックで EndInvoke が呼び出されるまでデリゲートは待機してから R を返します。また、各ケースで R が実際に割り当てられていることを確認するために、さらにチェックを使用することもできます。
public static Func<R> HandleInvoke<T, R>(this Func<T, R> function, T arg)
{
R r = default(R);
IAsyncResult asyncResult = function.BeginInvoke(arg, result =>
{
r = (result.AsyncState as Func<T, R>).EndInvoke(result);
}, function);
return delegate
{
while (!(asyncResult as AsyncResult).EndInvokeCalled)
{
Thread.Sleep(1);
}
return r;
};
}