2009-06-19 6 views
4

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.

Répondre

2

Basé sur le modèle ASync discuté sur la page que vous avez mentionnée, cela semble être une bonne tentative d'encapsulation de l'appel asynchrone. Ce qui me fait hésiter, c'est le nom de la méthode 'BeginConnect'; certaines classes .NET ont des paires 'BeginXxx'/'EndXxx' pour gérer les appels asynchrones, qui spécifient généralement que l'opération correcte requiert que l'appel 'EndXxx' est appelé depuis le gestionnaire de rappel, ce qui est quelque chose que votre système ne traite pas pour.

Si l'appel vous achevons ne sont effectivement conformes au modèle discuté sur la page liée, cela devrait fonctionner, si l'appel vous est un emballage du second genre que vous n'êtes pas tout à fait ...

+0

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. –

+0

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

+2

@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

Questions connexes