2010-09-18 11 views
6

He creado una consola para mi juego en XNA y tengo un delegado para cuando se ha ingresado un comando. En este momento, el delegado está devolviendo un valor bool. He declarado un evento dentro de la clase de la Consola (que devuelve falso) y luego me suscribí a este evento de otras clases. La idea es que si ninguna de las clases que se suscriben a este evento devuelve verdadero, se supone que el usuario ha ingresado un comando no válido. Sin embargo, si al menos una de las clases suscritas es verdadera, se supone que el comando es válido.C# "O" evento delegados que devuelven bool

Por el momento, solo se tiene en cuenta una clase para devolver verdadero o falso, ¿hay alguna manera de ver los valores devueltos de todas las clases subscritas O su resultado?

Gracias,

+1

Niza Q - AFAIK una asignación simple siempre devolverá el resultado del último suscriptor solamente. – StuartLC

Respuesta

3

lo he descubierto justo cuando me plantea esta pregunta: P

bool handled = false; 
foreach (Delegate d in CommandProcessed.GetInvocationList()) 
    handled |= (bool) d.DynamicInvoke (gameTime, command.ToString()); 

if (!handled) { } // Command Unrecognized 

Dónde CommandProcessed es mi caso de que se suscriben a clases.
Mi delegado toma dos argumentos: tiempo de juego y cadena de comandos.

+0

Sí, tuve que resolver este mismo problema recientemente para la validación encadenada. El operador bit a bit no cortocircuita como lo hace el booleano o el operador. – arootbeer

6

Desde dentro de la clase que declara el evento, se puede recuperar la invocación lista del evento (suponiendo un evento de campo similares). Invocar a cada uno de ellos individualmente le permitirá inspeccionar el valor de retorno de cada suscriptor del evento.

Por ejemplo:

public event Func<bool> MyEvent = delegate { return false; }; 

...  

private bool EmitMyEventAndReturnIfAnySubscriberReturnsTrue() 
{ 
    return MyEvent.GetInvocationList() 
        .Cast<Func<bool>>() 
        .Select(method => method()) 
        .ToList() //Warning: Has side-effects 
        .Any(ret => ret); 
} 

En este ejemplo, cada abonado es informado del evento - no cortocircuito se produce si cualquiera de ellos responde afirmativamente. Este comportamiento se puede cambiar fácilmente si lo desea eliminando la llamada al ToList().

Para ser sincero, no me gustan los eventos que devuelven valores; su semántica no es obvia para los suscriptores. Yo cambiaría el diseño si fuera posible.

EDIT: Error corregido al forzar la ejecución completa de la secuencia en función del comentario de Timwi.

+2

No se me habría ocurrido usar LINQ para esto. Buena respuesta. –

+0

Miré dos diseños diferentes y este fue el limpiador de ambos. Y es bastante fácil de entender e implementar. No estoy familiarizado con LinQ pero sí encontré una solución alternativa como lo describo a continuación. – Dave

+0

@Dave: la solución alternativa que ha publicado tiene la misma idea que mi respuesta: el truco es acceder a la lista de invocación. Estupendo. – Ani

0

Estoy de acuerdo con el problema acerca de los eventos que devuelven los valores, ya que también me parece desacertado. Sin embargo es una alternativa que podría crear una nueva clase CommandEventArgs:

class CommandEventArgs : EventArgs 
{ 
    public DateTime GameTime {get; set; } 
    public string Command {get; set;} 
    public bool Valid {get; set;} 
} 

a continuación, utilizar una instancia de este método para distribuir el evento y luego, si el oyente reconoce el comando tenerlo configurado Valid true. Por lo tanto, si Valid sigue siendo falso después de la invocación, sabrá que el comando no fue reconocido.

Así es como .NET maneja los eventos de teclado que ha configurado KeyEventArgs.Handled en true para suprimir cualquier acción futura que ocurra con el evento.