Я хочу перепроверить с другими, является ли это правильным способом создания метода расширения, который запускает асинхронный процесс и возвращает функцию, которая при вызове, по существу, ожидает этого процесса и получает результат.
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
Не был уверен, стоит ли мне беспокоиться об ожидании ожидания в этой ситуации или нет. Также не уверен, будет ли вообще необходим обратный вызов. Также я думаю, что это закрытие?
EDIT
Закончилось этим,
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. Thread.Sleep (), вероятно, не лучшее решение, хотя. Также можно использовать дополнительную проверку, чтобы убедиться, что 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;
};
}