Является ли этот метод преобразования асинхронного метода в синхронный правильным? - PullRequest
4 голосов
/ 19 июня 2009

У меня есть метод, реализованный с использованием шаблона Асинхронного метода на основе событий . Я также хочу предложить синхронную версию этого метода, но не хочу переписывать его (поскольку метод включает в себя вызов WCF из Silverlight, версия Async должна быть основным методом).

Я предложил следующий универсальный метод для преобразования асинхронного вызова на основе событий в синхронный:

 Func<TArg1, TArg2, TArg3, TEventArgs> 
    CreateSynchronousMethodFromAsync<TArg1, TArg2, TArg3, TEventArgs>(
       Action<TArg1, TArg2, TArg3, EventHandler<TEventArgs>> asyncMethod) 
         where TEventArgs : AsyncCompletedEventArgs
    {
        Func<TArg1, TArg2, TArg3, TEventArgs> syncMethod = (arg1, arg2, arg3) =>
         {
             TEventArgs eventArgs = null;

             using (var waitHandle = new ManualResetEvent(false))
             {
                 asyncMethod(arg1, arg2, arg3, (sender, e) =>
                                          {
                                              eventArgs = e;
                                              waitHandle.Set();
                                          });

                 waitHandle.WaitOne();

                 return eventArgs;
             }
         };

        return syncMethod;
    }

Итак, если у меня есть этот асинхронный метод:

void ConnectAsync(string address, 
     string userName, 
     string password, 
     EventHandler<ConnectCompletedEventArgs> completionCallback)

Я могу преобразовать его в синхронный вызов, например:

public void Connect(string address, string userName, string password)
{
    Func<string, string, string, ConnectCompletedEventArgs> connect = 
        CreateSynchronousMethodFromAsync<string, string, string, ConnectCompletedEventArgs>(ConnectAsync);

    var connectResult = connect(address, userName, password);

    if (connectResult.Error != null)
    {
        throw connectResult.Error;
    }
}

Меня беспокоит использование переменной eventArgs, которая фиксируется в замыкании. Он устанавливается в одном потоке и доступен из другого. Достаточно ли моего использования ManualResetEvent, чтобы гарантировать правильное считывание значения после сигнализации о событии, или мне нужно сделать что-то еще?

Ну, вы на этом, вы можете прокомментировать обработку исключений здесь. Мой план состоит в том, что метод Async обернет исключения, возникающие ниже в стеке, в ConnectionException, или что-то в этом роде, поэтому я думаю, что перебрасывание исключения является правильным в этом случае.

1 Ответ

2 голосов
/ 19 июня 2009

На основе шаблона ASync, обсуждавшегося на странице, на которую вы ссылались, это выглядит как довольно хорошая попытка обернуть асинхронный вызов.

Что заставляет меня сомневаться, так это название метода 'BeginConnect'; некоторые классы .NET имеют пары 'BeginXxx' / 'EndXxx' для обработки асинхронных вызовов, и они обычно указывают, что для правильной операции требуется , чтобы вызов 'EndXxx' вызывался из обработчика обратного вызова Это то, что ваша схема не обслуживает.

Если вызов, который вы упаковываете, фактически соответствует шаблону, обсуждаемому на связанной странице, это должно сработать, если вызов, который вы упаковываете, относится ко второму виду, которого вы не совсем там ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...