2009-08-06 5 views
13

Der Code sieht unten wie:Wenn ein Ereignis mehrere Abonnenten hat, wie bekomme ich den Rückgabewert für jeden Abonnenten?

Uhr:

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

um den Code auszuführen:

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

Die anderen Fragen sind:

  • Ist es für jeden Teilnehmer eine gute Praxis einen Wert zurückgeben?
  • Ist es eine gute Vorgehensweise, Action/Func einfach als Ereignisrückgabetyp zu deklarieren, anstatt einen Delegaten manuell zu deklarieren?

Antwort

26

Verwenden Sie Delegate.GetInvocationList.

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

ist es gute Praxis nur Action/Func anstelle von manuell einen Delegierten zu erklären?

Ja. Aber ich werde darauf hinweisen, dass die beste Praxis für Ereignisse ist, EventHandler<T> anstelle von Func<..., TResult> zu verwenden. EventHandler<T> unterstützt keine Rückgabewerte, aber Sie haben eine gewisse Berechtigung darin, dass einige .NET-Ereignisse Rückgabewerte haben. Ich würde es besser halten, eine einstellbare Eigenschaft in einer benutzerdefinierten EventArgs Unterklasse zu haben, die Sie als Ihre T verwenden. Dies ist das Muster, das wir in Dingen wie KeyEventArgs.Handled sehen. Auf diese Weise können Sie EventHandler<T> verwenden und die Abonnenten können ihre Antworten auch in begrenztem Umfang koordinieren, indem Sie diese Eigenschaft abrufen und festlegen.

+0

Ihnen sehr danken. – Jeff

+1

Nicht einverstanden. Das (Objekt Sender, EventArgs e) Muster ist voll von subtiler Güte. Siehe beide akzeptierte Antworten hier: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/83e9f2f4-908b-4679-811d-c5b1471730d7 –

+0

Ok, ich sehe Ihren Punkt. – Jeff

0

Ich denke, es ist vollkommen in Ordnung, Action/Func anstelle des Delegaten zu verwenden.

ABER Ereignisse sollen nicht so verwendet werden. Sie werden zu einem unbestimmten Zeitpunkt ausgelöst, so dass Sie nicht alle Parameter kennen.

Was Sie wirklich brauchen, ist wahrscheinlich:

  1. Verwendung Polymorphismus für die Uhr.
  2. Verwenden Sie Besucher-/Abonnenten-/Beobachtermuster, um ihre Werte zu erhalten.

So wird der Code wie folgt aussehen:

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