2012-06-10 12 views
6

Soy un principiante con C# y no puedo encontrar ninguna respuesta para esto:Cómo delegar la acción correcta <Interface>?

Im tratando de delegar acciones con algún parámetro de la interfaz, pero empujo a través de funciones con los objetos que se extienden esta interfaz (o clase)

// some class extending interface 
public class IntEvent : IFace{} 
public class MoveEvent : IFace{} 

// function i like to use to verify Action 
static void setAction(Action<IFace> evt) { 
    // evt ... 
} 
// function to delegate as Action 
static void evtCheck(IntEvent evt) { 
    // some func 
} 
static void evtMove(MoveEvent evt) { 
    // some func 
} 
// class { 
// call method inside class and delegate this function : 
setAction(evtCheck); 
setAction(evtMove); 

Recibo el error "evtCheck(IntEvent) no se puede convertir a Action<IFace>", incluso si IntEvent amplía la interfaz IFace.

¿Cómo debo solucionar esto? ¿Tal vez tengo que usar Func o Delegate?

Respuesta

7

No puede hacer lo que está tratando de hacer: espera la covarianza, pero Action<T> es contravariante en su único parámetro de tipo.

No se puede hacer una conversión método de grupo desde evtCheck a Action<IFace> porque evtChecknecesita un tipo más específico (IntEvent) como su argumento que el más general IFace tipo que una instancia Action<IFace> espera. Si se permitiera dicha conversión, ¿qué esperaría que ocurriera si el delegado se ejecutara con un argumento que implementa IFace pero no es un IntEvent?

Creo que debería echarle otro vistazo a su diseño porque parece que hay un defecto allí, pero si lo desea, puede crear una lambda para forzar un molde del argumento al tipo deseado y aceptar la posibilidad de un InvalidCastException:

setAction(iFace => evtCheck((IntEvent)iface)); 

Lo más probable, es posible que desee hacer evtCheck aceptar un tipo más general o setAction a aceptar un delegado más específico.

4

Action<T> es contravariante en T, por lo que los métodos que toman un Action<T> también aceptará Action<U> donde T se deriva de U.

Su clase IntEvent, sin embargo, implementa la interfaz IFace, lo que significa que si el compilador acepta su setAction() llamada, sería posible llamar al evtCheck() con un argumento que es otro IFace -derivativo y no IntEvent, un error de tiempo de ejecución y una clara violación del tipo de seguridad. referencia

obligatorio Eric Lippert: Covariance and contravariance

EDIT: desde su descripción me parece que lo que realmente quiere es la diferenciación basada en el tipo del parámetro de método, por lo que, por ejemplo, desea una acción separada para IntEvent, otra para (un hipotético) DoubleEvent etc. Si este es el caso, en realidad está después del envío virtual doble, que no se admite directamente en C#, pero puede simularlo usando el patrón de diseño Visitor .

+0

Sí, esto es lo que estoy tratando de hacer. Las funciones de acción siempre esperan un objeto que extienda la misma interfaz u objeto. Bien, miraré el patrón de diseño del visitante. – turbosqel

Cuestiones relacionadas