I have a method implemented using an Event-Based Asynchronous Method Template . I also want to offer a synchronous version of this method, but I do not want to rewrite it (since this method involves calling WCF from Silverlight, the Async version should be the main method).
I came up with the following general method for converting an event-based asynchronous call to synchronous:
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; }
So, if I have this asynchronous method:
void ConnectAsync(string address, string userName, string password, EventHandler<ConnectCompletedEventArgs> completionCallback)
I can convert it to a synchronous call like this:
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; } }
I am worried about the use of the eventArgs variable, which is captured in closure. It is installed in one thread and is accessible from another. Is my use of ManualResetEvent sufficient to guarantee that the value is correctly read after the event has been signaled, or do I need to do something else?
It's good that you are on it, you can comment on the handling of Exceptions. My plan is that the Async method will wrap exceptions that occur below on the stack in ConnectionException or something like that, so I believe that in this case the correct choice for Exception is correct.