2012-06-10 5 views
6

Ich bin ein Anfänger mit C# und jede Antwort auf diese nicht finden können:So delegieren Sie die richtige Aktion <Interface>?

Im Versuch, zu delegieren Aktionen mit einigen Schnittstellenparameter, sondern durchsetzen Funktionen mit Objekten, die diese Schnittstelle (oder Klasse) erweitern

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

Ich erhalte eine Fehlermeldung, dass "evtCheck(IntEvent) nicht in Action<IFace> konvertiert werden kann", auch wenn IntEvent die IFace Schnittstelle erweitert.

Wie soll ich das lösen? Vielleicht muss ich Func oder Delegate verwenden?

Antwort

7

Sie können nicht tun, was Sie zu tun versuchen - Sie erwarten Kovarianz, aber Action<T> ist kontra auf seinen einzigen Typ-Parametern.

Sie können keine Methode Gruppen Umwandlung evtCheck-Action<IFace> tun, weil evtCheck einen spezifischere Typen (IntEvent) als Argument als der allgemeinere IFace Typ benötigt, die eine Action<IFace> Instanz erwartet. Wenn eine solche Konvertierung zulässig wäre, was würden Sie erwarten, wenn der Delegat mit einem Argument ausgeführt würde, das IFace implementiert, aber kein IntEvent ist?

Ich denke, Sie sollten einen anderen Blick auf Ihr Design haben, weil es dort einen Fehler gibt, aber wenn Sie möchten, können Sie ein Lambda erstellen, um eine Umwandlung des Arguments zum gewünschten Typ zu erzwingen und die Möglichkeit eines zu akzeptieren InvalidCastException:

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

wahrscheinlicher ist, möchten Sie vielleicht evtCheck akzeptieren eine allgemeinere Art oder setAction zu akzeptieren, eine spezifischere Delegierten machen.

4

Action<T> ist kontra in T, so Methoden ein Action<T> nehmen auch Action<U> annehmen, wenn T von U. stammt

Ihre IntEvent Klasse implementiert jedoch die IFace Schnittstelle, was bedeutet, dass, wenn der Compiler akzeptiert Ihre setAction() Call, wäre es möglich, evtCheck() mit einem Argument, das eine andere IFace -derivative und nicht IntEvent, ein Laufzeitfehler und eine klare Verletzung der Typ Sicherheit.

obligatorische Eric Lippert Referenz: Covariance and contravariance

EDIT: Aus Ihrer Beschreibung scheint es mir, dass das, was Sie wirklich wollen, Differenzierung auf der Methodenparameter des Typs basiert, so z.B. Sie möchten eine separate Aktion für IntEvent, eine andere für (eine hypothetische) DoubleEvent usw. Wenn dies der Fall ist, sind Sie tatsächlich nach doppelten virtuellen Versand, der nicht direkt in C# unterstützt wird, aber Sie können es mit dem Visitor Entwurfsmuster simulieren .

+0

Ja, das ist was ich versuche zu tun. Aktionsfunktionen erwarten immer Objekte, die dieselbe Schnittstelle oder dasselbe Objekt erweitern. Ok, ich schaue mir das Besucherdesignmuster an. – turbosqel

Verwandte Themen