J'ai une méthode implémentée en utilisant le Event-based Asynchronous method pattern. Je veux également offrir une version synchrone de cette méthode, mais je ne veux pas la réécrire (parce que la méthode implique un appel à WCF à partir de Silverlight, la version Async doit être la méthode principale).Cette méthode de conversion d'une méthode asynchrone en une méthode synchrone est-elle correcte?
Je suis venu avec la méthode générique suivante pour convertir un appel asynchrone basé sur des événements à un synchrone:
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;
}
Donc, si j'ai cette méthode asynchrone:
void ConnectAsync(string address,
string userName,
string password,
EventHandler<ConnectCompletedEventArgs> completionCallback)
I peut le convertir en un appel synchrone comme ceci:
Mon souci est sur les États-Unis e de la variable eventArgs qui est capturée dans la fermeture. Il est défini dans un thread, et accessible à partir d'un autre. ManualResetEvent est-il suffisant pour garantir une lecture correcte de la valeur une fois que l'événement a été signalé ou dois-je faire autre chose?
Eh bien vous y êtes, vous voudrez peut-être commenter sur la gestion des exceptions ici. Mon plan est que la méthode Async enveloppera les exceptions qui se produisent plus bas dans la pile dans une ConnectionException, ou quelque chose comme ça, donc je pense que la réitération de l'Exception est correcte dans ce cas.
Mon code est conçu uniquement pour une utilisation avec des méthodes conformes au modèle de méthode asynchrone de base d'événements - ma méthode interne, BeginConnect, dont l'implémentation n'est pas montrée, s'occupe de terminer les appels Begin/End. –
Notez qu'au lieu de 'throw connectionResult.Error', vous pouvez inclure cette exception interne dans une nouvelle exception afin que la trace de pile de l'exception d'origine soit conservée. – jerryjvl
@Sam: Je vous recommande de nommer la méthode basée sur la convention dans l'article lié, pour éviter toute confusion ... faites plutôt 'ConnectAsync'. – jerryjvl