Вы должны понимать, что как только вы вводите асинхронную операцию в последовательность, вся последовательность становится асинхронной.Использование таких методов блокирования, как Sleep
, на 99,9999% является неправильным выбором.
Перестройка как: -
private void GetHandlers(int handlerID, Action<IList<Handler>> returnResult)
{
EventHandler<GetHandlersCompletedEventArgs> eh = null;
eh = (s, args) =>
{
WebSerive.GetHandlersCompleted -= eh;
returnResult(args.Result);
};
WebSerive.GetHandlersCompleted += eh;
WebSerive.GetHandlersAsync(handerlID);
}
, после чего вы вызываете: -
GetHandlers(_app.HandlerId, handlers =>
{
_handlers = handlers;
// Do other stuff
});
Edit
Позвольте мне на концептуальном уровне обрисовать, в чем заключается основная проблема.Допустим, у меня есть событие нажатия кнопки, которое вызывает FuncA
.FuncA
звонки FuncB
, FuncB
звонки FuncC
.
щелчок -> FuncA -> FuncB -> FuncC
Вся эта последовательность синхронна этоможет выглядеть так: -
void Button_Click(object sender, EventArgs e)
{
FuncA();
//Do other stuff
}
void FuncA()
{
var result = FuncB();
//Do stuff with result;
}
string FuncB()
{
return FuncC() + " World";
}
string FuncC()
{
return "Hello";
}
Но теперь давайте изменим FuncC
на что-то, что работает асинхронно.Он возвращает немедленно, но его возвращаемое значение недоступно до тех пор, пока не будет выполнено, он вызывает метод обратного вызова, когда завершается, который несет результат в качестве параметра.Проблема для FuncB
состоит в том, что он хочет вернуть значение, но не может, пока не завершится асинхронная операция FuncC
.Вместо того, чтобы FuncB
блокировать поток, нам нужно превратить FuncB
в асинхронную операцию так же, как FuncC
.Весь этот процесс должен пройти весь путь к событию.Он становится: -
void Button_Click(object sender, EventArgs e)
{
FuncA(() =>
{
//Do other stuff after FuncA has completed
});
}
void FuncA(Action callback)
{
FuncB(result =>
{
//Do stuff with result
// then finally
callback();
});
}
void FuncB(Action<string> returnResult)
{
FuncC(result => returnResult(result + " World"));
}
void FuncC(Action<string> returnResult)
{
Dispatcher.BeginInvoke(() => returnResult("Hello"));
}
Этот шаблон будет работать, когда задействована только одна фактическая асинхронная операция.Вещи начинают становиться действительно прикольными, когда вы выполняете серию реальных асинхронных вызовов в одной и той же операции.Чтобы избежать чрезмерного вложения колбэков, нужна небольшая помощь.Я называю мой AsyncOperationService
, о котором вы можете прочитать здесь .