2009-06-01 10 views
7

Ma classe a un événement qui objets externes souscrira à:Transfert/relayer les événements .NET

public event EventHandler<MessageReceivedEventArgs> MessageReceived; 

Cependant, un objet Listener interne, en cours d'exécution sur son propre fil, sera effectivement l'origine de l'événement.

private class Listener 
{ 
    public void Run() 
    { 
     // events raised here which should be forwarded 
     // to parent's MessageReceived 
    } 
}; 

Mon inclination est de créer un événement avec la même signature sur le Listener, et souscrire dans la classe principale pour le porter sur MessageReceived. Cela semble un peu lourd, alors je me demandais s'il y avait une façon nette/idiomatique de transmettre des événements comme celui-ci.

Répondre

22

Vous pouvez utiliser l'événement add/remove accessors pour que les événements câblés à l'événement orientées vers l'extérieur sont « transmis » à l'auditeur interne

public event EventHandler<MessageReceivedEventArgs> MessageReceived { 
    add { this.listener.MessageRecieved += value; } 
    remove { this.listener.MessageRecieved -= value; } 
} 

Cela signifie que vous devez créer un événement dans l'auditeur, mais l'avantage est qu'il n'y a pas d'autre tuyauterie pour câbler l'événement.

+8

Ceci est une bonne solution, mais sachez que le gestionnaire d'événements recevra l'instance de l'écouteur comme argument de l'expéditeur, ce qui peut poser problème ... –

+0

Nice, j'aime ça! – marijne

+1

Egalement un bon point sur l'expéditeur ... – marijne

1

Vous pouvez le faire avec un événement, ou vous pouvez créer une méthode dans votre classe principale appelée ReceiveMessage() et l'appeler depuis l'écouteur (puis déclencher l'événement à partir de là).

1

Comme il a été répondu, vous pouvez avoir une logique d'abonnement personnalisée en utilisant ajouter et supprimer des gestionnaires sur votre événement.

Notez que cette conception a un problème tel quel. Vous spécifiez que votre écouteur lève l'événement dans son propre thread. Par défaut, les gestionnaires seront appelés sur le thread qui a déclenché l'événement (dans votre cas, le thread de l'auditeur). Vous avez plusieurs options.

  • Si vous ne voulez pas que le thread d'écoute exécute les rappels. Appelez simplement l'événement en l'état (mais votre thread d'écoute peut être bloqué si un gestionnaire d'événement met du temps à s'exécuter, ou s'il meurt si un gestionnaire d'événement renvoie une exception non gérée)
  • Si vous souhaitez que les gestionnaires s'exécutent dans des threads différents de ceux de l'écouteur thread, mais ne vous souciez pas des threads tant que ce n'est pas dans l'écouteur: dans la méthode OnXXX qui appelle réellement les gestionnaires, récupérez la liste d'invocation de l'événement et mettez en file d'attente chaque gestionnaire dans le pool de threads.
  • Si vous voulez que les gestionnaires soient appelés threads spécifiques: un peu délicat, vous devez utiliser un SynchronizationContext (WindowsSynchronizationContext dans Winforms, une coutume un dans d'autres cas, etc.)

Il y a un billet de blog par Roy Osherove montrant plusieurs façons de faire les appels asynchrones: http://weblogs.asp.net/rosherove/pages/DefensiveEventPublishing.aspx (mais je n'utiliserais pas les appels asynchrones sur les délégués et je m'en remettrais directement au ThreadPool pour appeler les délégués).

Questions connexes