2009-08-06 12 views
13

El código se parece a continuación:cuando un evento tiene múltiples suscriptores, ¿cómo obtengo el valor de retorno para cada suscriptor?

Reloj

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

para ejecutar el código:

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

Las otras preguntas son:

  • ¿Es una buena práctica para cada suscriptor para devolver un valor?
  • ¿Es una buena práctica declarar Action/Func como el tipo de devolución de evento en lugar de declarar manualmente un delegado?

Respuesta

26

Uso Delegate.GetInvocationList.

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

es una buena práctica sólo tiene que utilizar Acción/Func manualmente en lugar de declarar un delegado?

Sí. Pero señalaré que la mejor práctica es que los eventos usen EventHandler<T> en lugar de Func<..., TResult>. EventHandler<T> no admite valores devueltos, pero está algo justificado en cuanto a que hay algunos eventos .NET que tienen valores devueltos. Considero que es mejor tener una propiedad configurable en una subclase personalizada EventArgs que utilice como su T. Este es el patrón que vemos en cosas como KeyEventArgs.Handled. De esta forma, puede usar EventHandler<T> y los suscriptores también pueden coordinar sus respuestas de forma limitada obteniendo y configurando esta propiedad.

+0

Muchas gracias. – Jeff

+1

No estoy de acuerdo. El patrón (objeto remitente, EventArgs e) está lleno de bondad sutil. Ver tanto de las respuestas aceptadas aquí: http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/83e9f2f4-908b-4679-811d-c5b1471730d7 –

+0

Ok, veo su punto. – Jeff

0

creo que es perfectamente posible utilizar Acción/Func en lugar del delegado.

pero no se supone Eventos para ser utilizado por el estilo. Se activan en un punto de tiempo indefinido, por lo que simplemente no conoce todos los parámetros.

Lo que realmente necesita es probablemente:

  1. Uso de polimorfismo para el reloj.
  2. Usa patrones de visitante/suscriptor/observador para obtener sus valores.

Así que el código se verá así:

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