2009-08-06 10 views
13

Il codice si presenta come di seguito:quando un evento ha più abbonati, come posso ottenere il valore di ritorno per ciascun iscritto?

Clock:

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; 
    } 
} 

per eseguire il codice:

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

Le altre domande sono:

  • E 'buona pratica per ogni abbonato di restituire un valore?
  • È buona norma dichiarare Action/Func come tipo di ritorno di evento invece di dichiarare manualmente un delegato?

risposta

26

Utilizzare Delegate.GetInvocationList.

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

è una buona pratica utilizzare solo Azione/Funz invece di dichiarare manualmente un delegato?

Sì. Ma farò notare che la migliore prassi è che gli eventi utilizzino lo EventHandler<T> anziché lo Func<..., TResult>. EventHandler<T> non supporta i valori restituiti, ma si è in qualche modo giustificati nel fatto che ci sono alcuni eventi .NET con valori di ritorno. Lo considererei migliore per avere una proprietà impostabile in una sottoclasse personalizzata EventArgs che si utilizza come T. Questo è lo schema che vediamo in cose come KeyEventArgs.Handled. In questo modo, è possibile utilizzare EventHandler<T> e gli abbonati possono anche coordinare le loro risposte in misura limitata ottenendo e impostando questa proprietà.

+0

La ringrazio molto. – Jeff

+1

Non accetto. Il modello (oggetto mittente, EventArgs e) è pieno di sottile bontà. Vedi entrambe le risposte accettate qui: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/83e9f2f4-908b-4679-811d-c5b1471730d7 –

+0

Ok, capisco il tuo punto. – Jeff

0

Penso che sia perfettamente corretto utilizzare Action/Func al posto del delegato.

MA Gli eventi non dovrebbero essere usati così. Sono attivati ​​a un tempo indefinito, quindi non si conoscono tutti i parametri.

cosa si ha realmente bisogno è probabilmente:

  1. utilizzare il polimorfismo per l'orologio.
  2. Utilizzare i pattern visitatore/sottoscrittore/osservatore per ottenere i propri valori.

Quindi il codice sarà simile:

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