Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/306.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 这种将异步方法转换为同步方法的方法正确吗?_C#_Multithreading_Asynchronous_Closures - Fatal编程技术网

C# 这种将异步方法转换为同步方法的方法正确吗?

C# 这种将异步方法转换为同步方法的方法正确吗?,c#,multithreading,asynchronous,closures,C#,Multithreading,Asynchronous,Closures,我已经有了一个使用实现的方法。我还想提供该方法的同步版本,但不想重新编写它(因为该方法涉及从Silverlight调用WCF,异步版本必须是主要方法) 我提出了以下通用方法将基于事件的异步调用转换为同步调用: Func<TArg1, TArg2, TArg3, TEventArgs> CreateSynchronousMethodFromAsync<TArg1, TArg2, TArg3, TEventArgs>( Action<TArg1

我已经有了一个使用实现的方法。我还想提供该方法的同步版本,但不想重新编写它(因为该方法涉及从Silverlight调用WCF,异步版本必须是主要方法)

我提出了以下通用方法将基于事件的异步调用转换为同步调用:

 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;
    }
Func
CreateSynchronousMethodFromAsync(
行动(方法)
其中TEventArgs:AsyncCompletedEventArgs
{
Func syncMethod=(arg1、arg2、arg3)=>
{
TEventArgs eventArgs=null;
使用(var waitHandle=新手动重置事件(错误))
{
异步方法(arg1、arg2、arg3,(发送方,e)=>
{
eventArgs=e;
waitHandle.Set();
});
waitHandle.WaitOne();
返回事件参数;
}
};
返回同步方法;
}
如果我有这个异步方法:

void ConnectAsync(string address, 
     string userName, 
     string password, 
     EventHandler<ConnectCompletedEventArgs> completionCallback)
void ConnectAsync(字符串地址,
字符串用户名,
字符串密码,
EventHandler 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;
    }
}
public void Connect(字符串地址、字符串用户名、字符串密码)
{
Func connect=
CreateSynchronousMethodFromAsync(ConnectAsync);
var connectResult=connect(地址、用户名、密码);
if(connectResult.Error!=null)
{
抛出连接结果。错误;
}
}
我关心的是在闭包中捕获的eventArgs变量的使用。它被设置在一个线程中,并从另一个线程访问。我使用ManualResetEvent是否足以保证在发出事件信号后正确读取值,或者我是否需要执行其他操作


好了,您可能想在这里对异常的处理进行评论。我的计划是,Async方法将在ConnectionException或类似的东西中包装堆栈下层发生的异常,因此我的想法是,在这种情况下,重新引发异常是正确的。

基于您提到的页面上讨论的异步模式,这看起来是包装异步调用的一个很好的尝试

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


如果您正在包装的调用实际上符合链接页面上讨论的模式,那么这应该是可行的,如果您正在包装的调用是第二种类型的调用之一,您还不太清楚……

我的代码仅设计用于符合事件基异步方法模式的方法-我的内部方法BeginConnect,我没有展示它的实现,负责包装开始/结束调用。请注意,您可能希望将其作为内部异常包装到新异常中,而不是“throw connectionResult.Error”,以便保留原始异常的堆栈跟踪。@Sam:我建议根据链接文章中的约定命名该方法,以避免混淆。。。改为“ConnectAsync”。