2012-06-10 2 views
6

Sono un principiante con C# e non riesco a trovare alcuna risposta per questo:Come delegare l'azione corretta <Interface>?

Nel tentativo di delegare azioni con alcuni parametri di interfaccia, ma spingere attraverso funzioni con oggetti che si estendono questa interfaccia (o classe)

// 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); 

Ricevo un errore che "evtCheck(IntEvent) non può essere convertito in Action<IFace>", anche se IntEvent estende l'interfaccia IFace.

Come dovrei risolvere questo? Forse devo usare Func o Delegate?

risposta

7

Non si può fare quello che stai cercando di fare - covarianza ti aspetti, ma è Action<T>contravariant il suo unico tipo di parametro.

Non si può fare una conversione metodo-gruppo dal evtCheck a Action<IFace> perché evtCheck bisogno di un tipo più preciso (IntEvent) come argomento del IFace tipo più generale che un'istanza Action<IFace> aspetta. Se tale conversione fosse consentita, cosa ti aspetteresti che accada se il delegato è stato eseguito con un argomento che implementa IFace ma non è un IntEvent?

Penso che dovresti dare un'altra occhiata al tuo progetto perché sembra che ci sia un difetto lì, ma se vuoi, puoi creare un lambda per forzare un cast dell'argomento al tipo desiderato e accettare la possibilità di un InvalidCastException:

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

più probabilmente, si potrebbe desiderare di fare evtCheck accettare un tipo più generale o setAction ad accettare un delegato più specifica.

4

Action<T> è contravariant a T, quindi i metodi che prendono un Action<T> sarà anche accettare Action<U> dove T è derivato da U.

La classe IntEvent, però, implementa l'interfaccia IFace, il che significa che se il compilatore ha accettato il tuo setAction() chiamata, sarebbe possibile chiamare evtCheck() con un argomento che è un altro IFace -derivativo e non IntEvent, un errore di runtime e una chiara violazione della sicurezza del tipo. riferimento

obbligatorio Eric Lippert: Covariance and contravariance

EDIT: dalla tua descrizione mi sembra che ciò che si vuole veramente è la differenziazione in base al tipo del parametro del metodo, così per esempio vuoi un'azione separata per IntEvent, un'altra per (un ipotetico) DoubleEvent ecc. Se questo è il caso, sei effettivamente dopo il doppio invio virtuale, che non è direttamente supportato in C#, ma puoi simularlo usando il modello di progettazione Visitor .

+0

Sì, questo è quello che sto cercando di fare. Le funzioni di azione si aspettano sempre oggetti che estendono la stessa interfaccia o oggetto. Ok, guarderò il modello di progettazione dei visitatori. – turbosqel