我有一个使用
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的使用是否足以保证在发出事件信号后正确读取值,或者我是否需要执行其他操作?
那么你就是这样,你可能想在这里评论一下Exception的处理方式.我的计划是Async方法将在ConnectionException中包装发生在堆栈下方的异常,或类似的东西,所以我的想法是在这种情况下重新抛出异常是正确的.
最佳答案 基于您所引用的页面上讨论的ASync模式,这看起来非常适合包装异步调用.
然而,让我犹豫的是’BeginConnect’方法的名称;一些.NET类具有’BeginXxx’/’EndXxx’对来处理异步调用,这些通常指定正确的操作要求从回调处理程序调用’EndXxx’调用,这是您的方案不能满足的.
如果您正在包装的电话确实符合链接页面上讨论的模式,那么这应该有效,如果您正在包装的电话是第二种类型之一,那么您不在那里…