这种将异步方法转换为同步方法的方法是否正确?

时间:2009-06-19 08:43:21

标签: c# multithreading asynchronous closures

我有一个使用Event-based Asynchronous method pattern实现的方法。我也想提供该方法的同步版本,但不想重写它(因为该方法涉及从Silverlight调用WCF,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 个答案:

答案 0 :(得分:2)

基于您所引用的页面上讨论的ASync模式,这看起来非常适合包装异步调用。

然而,让我犹豫的是方法'BeginConnect'的名称;一些.NET类具有“BeginXxx”/“EndXxx”对来处理异步调用,这些通常指定正确的操作需要表示“EndXxx”调用是从回调处理程序调用的,这是你的方案不能满足的。

如果您正在包装的电话确实符合链接页面上讨论的模式,那么这应该有效,如果您正在包装的电话是第二种类型之一,那么您不在那里......