Проблема с выполнением асинхронного метода - PullRequest
1 голос
/ 08 сентября 2011

У меня проблема с этим кодом

 if(Handlers.Count==0)
                {
                    GetHandlers();
                    while (_handlers.Count == 0)
                    {
                        Thread.Sleep(100);
                    }
                }
                return _showroomLogs;

Этот метод выполняет:

 private void GetHandlers()
        {
            WebSerive.GetHandlersCompleted += new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
            WebSerive.GetHandlersAsync(_app.HandlerId);
        }

но к этому методу:

private void OnGetHandlersCompleted(object sender, GetHandlersCompletedEventArgs e)
        {
            WebSerive.GetHandlersCompleted -= new EventHandler<GetHandlersCompletedEventArgs>(OnGetHandlersCompleted);
            _handlers = e.Result;
        }

Я попал в последующее исполнение

return _showroomLogs;

конечно, если я уберу этот кусок с Пока

Что я должен сделать, чтобы выполнить OnGetHandlersAsync до

 return _showroomLogs;

1 Ответ

1 голос
/ 09 сентября 2011

Вы должны понимать, что как только вы вводите асинхронную операцию в последовательность, вся последовательность становится асинхронной.Использование таких методов блокирования, как 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, о котором вы можете прочитать здесь .

...