2017-06-29 4 views
2

Ich suche nach einem Delegaten, der eine Methode einkapselt, die keinen Wert zurückgibt und einen Parameter wie Aktion < T> leider der Fall ist, sondern dass Delegierte nicht mit der Methode Aufnahme eines Kind Typ als Parameter ...C# -Delegat für Funktion mit keinem Rückgabewert und einen Parameter, der Untertypklassen erlaubt (als Parameter)

das ist, was ich versuche zu tun überein:

public class BaseType 
{ 
    public BaseType() 
    { 

    } 
} 
public class ChildType : BaseType 
{ 
    public ChildType() 
    { 

    } 
} 
public class Test 
{ 

public delegate void CallBackHandler(BaseType p); 

    public Test() 
    { 
     CallBackHandler clbk1 = callBackA; 
     CallBackHandler clbk2 = callBackB; //That line does not compile 
              //->'No overload for 'callBackB' matches delegate 'Test.CallBackHandler' 
    } 

    private void callBackA(BaseType p) 
    { 

    } 

    private void callBackB(ChildType p) 
    { 

    } 
} 

ich las über Kovarianz, Kontra, etc ... Ich weiß, es geht um ihn Rited Casting, aber ich bin ein wenig verwirrt über all dies ...

Welchen Delegaten sollte ich verwenden, um meinen Code arbeiten zu lassen?

+0

Mögliche Lösung: 'Callbackhandler clbk2 = p => callBackB (p);' – Fruchtzwerg

Antwort

1

Dies ist das Sicherheitsproblem des klassischen Typs, das zur Lösung entwickelt wurde.

Hier ist ein Beispiel

abstract class Vehicle 
{ 
    public virtual void MethodSlot1_StartEngine() { } 

    public virtual void MethodSlot2_StopEngine() { } 
} 

class Car : Vehicle 
{ 
    public virtual void MethodSlot3_OpenGasTank() { } 
} 

class NuclearSubmarine : Vehicle 
{ 
    public virtual void MethodSlot3_FireAllNuclearMissiles() { } 
} 

class VehicleUser 
{ 
    public delegate void OpenGasTankMethod(Car car); 

    public void OpenGasTank(Vehicle vehicle, OpenGasTankMethod method) 
    { 
     //it's stopping you here from firing all nuclear weapons 
     //by mistaking your car's gas tank for the armageddon switch 
     method(vehicle); 
    } 
} 

Wenn der Compiler eine virtuelle Methode aufrufen, gibt sie nur einen Index in einer Lookup-Tabelle erstellt. Wenn Sie ein NuclearSubmarine, wo ein Auto benötigt wird, nur weil sie beide Fahrzeuge sind, dann könnten Sie denken, Sie rufen Car-Methoden (wie das Öffnen Ihres Gastanks), wenn Sie in der Tat machen nur die Reihe von Spielen a Wirklichkeit.

Als Antwort auf Ihren Kommentar, sollte dies Ihnen den Einstieg:

class Blah 
{ 
    private List<Action<object>> _handlers = new List<Action<object>>(); 

    public void AddListener<T>(Action<T> handler) 
    { 
     //graceful type checking code goes in here somewhere 
     _handlers.Add(o => handler((T) o)); 
    } 

    void RaiseEvent(object eventArgs) 
    { 
     foreach (var handler in _handlers) handler(eventArgs); 
    } 
} 
+1

ich die Logik verstehen ... Ich Ich versuche tatsächlich, ein benutzerdefiniertes Ereignissystem zu implementieren, das wie JavaScript/AS3 aussieht, mit einer addEventListener (MyEventName, myCallbackMethod) -Registrierungsmethode, die alle Bearbeitungsmethoden, die ein Event annehmen, *** oder einem herited-Typ von Event übergeben kann ** *, als Parameter. Ich nehme an, es ist nicht möglich ...: ( Thx für Ihre Antworten – LePioo

+0

@LePioo - Noch ein Vorschlag - Sie könnten die Event-Handler, die Sie erhalten, in einen eigenen Wrapper-Handler schreiben, der sicherstellt, dass der Typ das ist Der Handler des Benutzers erwartet, bevor er aufgerufen wird, oder wickelt den Aufruf des Benutzerhandlers in einen Versuch, die InvalidCastException abzufangen, wenn die Typen falsch sind (obwohl das weniger effizient ist, die Type-Daten für die Parameter irgendwo zu speichern und Type.IsAssignableFrom zu überprüfen). argument.GetType()); – hoodaticus

+0

@LePioo - Ich habe meine Antwort aktualisiert, um Startcode für Ihren Anwendungsfall zu geben. – hoodaticus

1

Sie können dies nicht tun, da es nicht sicher ist. Wenn es erlaubt wurden, konnten Sie tun:

class OtherChild : BaseType { } 

CallBackHandler clbk2 = callBackB; 
clbk2(new OtherChild()); 

und eine Instanz von OtherChild an einen Delegierten übergeben, die eine Instanz von ChildType erfordert. Beachten Sie, dass die folgende sicher ist und kompiliert:

public delegate void CallBackHandler(ChildType p); 

CallBackHandler clbk1 = callBackA; 
CallBackHandler clbk2 = callBackB; 
1

den Delegierten erklären als

public delegate void CallBackHandler(ChildType p) 

Wenn der Handler akzeptieren könnte und auf Instanzen von BaseType handeln sollte, was passiert, wenn Sie in einer Instanz übergeben würde passieren, von eine neue Klasse NewChildType? Niemand weiß, weshalb Sie nicht hier sein können.

Verwandte Themen