2009-08-06 6 views
13

Le code ressemble ci-dessous:Lorsqu'un événement a plusieurs abonnés, comment puis-je obtenir la valeur de retour pour chaque abonné?

Horloge:

public class Clock 
{ 
    public event Func<DateTime, bool> SecondChange; 

    public void Run() 
    { 
     for (var i = 0; i < 20; i++) 
     { 
      Thread.Sleep(1000); 

      if (SecondChange != null) 
      { 
       //how do I get return value for each subscriber? 
       Console.WriteLine(SecondChange(DateTime.Now)); 
      } 
     } 
    } 
} 

DisplayClock:

public class DisplayClock 
{ 
    public static bool TimeHasChanged(DateTime now) 
    { 
     Console.WriteLine(now.ToShortTimeString() + " Display"); 
     return true; 
    } 
} 

LogClock:

public class LogClock 
{ 
    public static bool WriteLogEntry(DateTime now) 
    { 
     Console.WriteLine(now.ToShortTimeString() + " Log"); 
     return false; 
    } 
} 

Pour exécuter le code:

var theClock = new Clock(); 
theClock.SecondChange += DisplayClock.TimeHasChanged; 
theClock.SecondChange += LogClock.WriteLogEntry; 
theClock.Run(); 

Les autres questions sont:

  • Est-il une bonne pratique pour chaque abonné pour renvoyer une valeur?
  • Est-ce une bonne pratique de simplement déclarer Action/Func comme type de retour d'événement au lieu de déclarer manuellement un délégué?

Répondre

26

Utiliser Delegate.GetInvocationList.

if (SecondChange != null) 
{ 
    DateTime now = DateTime.Now; 
    foreach (Delegate d in SecondChange.GetInvocationList()) 
    { 
     Console.WriteLine(d.DynamicInvoke(now)); 
    } 
} 

est une bonne pratique d'utiliser simplement Action/Func au lieu de déclarer manuellement un délégué?

Oui. Mais je ferai remarquer que la meilleure pratique est que les événements utilisent EventHandler<T> au lieu de Func<..., TResult>. EventHandler<T> ne prend pas en charge les valeurs de retour, mais vous êtes justifié en ce sens qu'il existe quelques événements .NET qui ont des valeurs de retour. Je considère qu'il est préférable d'avoir une propriété réglable dans une sous-classe personnalisée EventArgs que vous utilisez comme T. C'est le modèle que nous voyons dans les choses comme KeyEventArgs.Handled. De cette façon, vous pouvez utiliser EventHandler<T> et les abonnés peuvent également coordonner leurs réponses dans une mesure limitée en obtenant et en définissant cette propriété.

+0

Merci beaucoup. – Jeff

+1

En désaccord. Le modèle (expéditeur d'objet, EventArgs e) est plein de subtilité. Voir les deux réponses acceptées ici: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/83e9f2f4-908b-4679-811d-c5b1471730d7 –

+0

Ok, je vois votre point. – Jeff

0

Je pense qu'il est parfaitement bien d'utiliser Action/Func au lieu du délégué.

MAIS Les événements ne sont pas censés être utilisés comme ça. Ils sont déclenchés à un point de temps indéfini, vous ne connaissez donc pas tous les paramètres.

Qu'est-ce que vous avez vraiment besoin est probablement:

  1. Utilisez polymorphisme pour l'horloge.
  2. Utilisez les modèles visiteur/abonné/observateur pour obtenir leurs valeurs.

Ainsi, le code ressemblera:

var theClock = new Clock(); 
theClock.AddSecondsSubscriber(new DisplayClock()); 
theClock.AddSecondsSubscriber(new LogClock()); 
theClock.RunAndExecuteVisitors(theBoolResultYouNeed => Console.WriteLine(theBoolResultYouNeed)); 
Questions connexes