9 Stimmen

Auslösen von Ereignissen der Basisklasse in abgeleiteten Klassen C#

Ich habe eine Basisklasse DockedToolWindow : Form, und viele Klassen, die von DockedToolWindow ableiten. Ich habe eine Containerklasse, die Ereignisse zu DockedToolWindow-Objekten hält und zuweist, aber ich möchte die Ereignisse von der Kindklasse aufrufen.

Ich habe eigentlich eine Frage dazu, wie man das umsetzen kann, was hier MSDN-Website mir sagt, was ich tun soll. Dieser Abschnitt unten bereitet mir Probleme:

    // The event. Note that by using the generic EventHandler<T> event type
    // we do not need to declare a separate delegate type.
    public event EventHandler<ShapeEventArgs> ShapeChanged;

    public abstract void Draw();

    //The event-invoking method that derived classes can override.
    protected virtual void OnShapeChanged(ShapeEventArgs e)
    {
        // Make a temporary copy of the event to avoid possibility of
        // a race condition if the last subscriber unsubscribes
        // immediately after the null check and before the event is raised.
        EventHandler<ShapeEventArgs> handler = ShapeChanged;
        if (handler != null)
        {
            handler(this, e);
        }
    }

Sicher dieses Beispiel kompiliert und funktioniert, aber wenn ich ersetzen "ShapeChanged" mit "Move" (ein Ereignis, das ich von der Ableitung von Form erworben), es Fehler sagen, ich kann nicht Move auf der rechten Seite ohne += oder -=. Ich habe auch die ShapeEventArgs generische Tags entfernt.

Gibt es Hinweise darauf, warum das nicht funktioniert? Was ist der Unterschied zwischen einem Ereignis, das innerhalb der Klasse deklariert ist, und einem, das vererbt wird?

12voto

Groo Punkte 47623

Sie können Ereignisse der Basisklasse nicht direkt auslösen. Das ist genau der Grund, warum Sie Ihre OnShapeChanged Methode protected anstelle von private .

Utilice base.OnMove() stattdessen.

4voto

Charlie Punkte 42390

Aus der C#-Sprachbeschreibung, Abschnitt 10.7 (Hervorhebung hinzugefügt):

Innerhalb des Programmtextes der Klasse oder Struktur, die die Deklaration eines Ereignisses enthält, können bestimmte Ereignisse wie Felder verwendet werden . Um auf diese Weise verwendet werden zu können, darf ein Ereignis nicht abstrakt oder extern sein und darf nicht explizit Ereignis-Zugriffsdeklarationen enthalten. Ein solches Ereignis kann in jedem Kontext verwendet werden, der ein Feld zulässt. Das Feld enthält einen Delegaten (§15), der sich auf die Liste der Ereignisbehandler bezieht, die dem Ereignis hinzugefügt wurden. Wurden keine Ereignishandler hinzugefügt, enthält das Feld den Wert Null.

Der Grund dafür, dass Sie das Ereignis "Move" nicht wie ein Feld behandeln können, ist, dass es in einem anderen Typ definiert ist (in diesem Fall in Ihrer Oberklasse). Ich schließe mich der Vermutung von @womp an, dass die Designer diese Entscheidung getroffen haben, um unbeabsichtigtes Herumspielen mit dem Ereignis zu verhindern. Es scheint offensichtlich schlecht zu sein, nicht verwandten Typen (Typen, die nicht von dem Typ, der das Ereignis deklariert, abgeleitet sind) zu erlauben, dies zu tun, aber selbst für abgeleitete Typen ist es vielleicht nicht wünschenswert. Wahrscheinlich hätte man eine Syntax einfügen müssen, die es erlaubt, die Ereignisdeklaration zu machen private o protected in Bezug auf die feldmäßige Verwendung, so dass ich vermute, dass sie sich dafür entschieden haben, es einfach ganz zu verbieten.

3voto

womp Punkte 113535

Der Unterschied liegt im Umfang. Innerhalb Ihrer Klasse können Sie kontrollieren, wie Ihre Ereignisdelegierten behandelt werden, aber Ihre Klasse kann nicht kontrollieren, was die Basisklasse tut. Sie könnte hinter den Kulissen einige verrückte Dinge mit dem Ereignis und seinen Handlern anstellen. Wenn Sie das Ereignis "Move" einfach "neu zuweisen", würden Sie die Multicast-Delegiertenliste für das Ereignis löschen.

Ich vermute, sie setzen eine Compiler-Beschränkung auf diese, weil seine eine sehr unsichere Praxis, und würde im Wesentlichen geben jeder Nachkomme Klasse die Fähigkeit, das Ereignis-Modell seiner Eltern zu zerstören.

1voto

David Pope Punkte 6229

Sie brauchen nur den Code, den Sie in der Klasse geschrieben haben, in der das Ereignis selbst definiert ist. Alle abgeleiteten Klassen sollten einfach OnShapeChanged() oder OnMove() direkt aufrufen, ohne das Kopieren usw., so dass Sie diesen Code überhaupt nicht in Ihren Klassen schreiben sollten (da das Ereignis Move in der Basisklasse definiert ist).

Wenn Sie irgendeine Art von Verarbeitung in der abgeleiteten Klasse durchführen müssen (vielleicht müssen Sie mit Ihrer Auflistungsklasse herumspielen?), überschreiben Sie den virtuellen OnXXX-Aufruf und führen Sie Ihre Aufgaben aus, bevor Sie base.OnXXX() aufrufen. Im MSDN-Artikel entspricht die Circle-Klasse Ihrer DockedToolWindow-Klasse. Das gleiche Muster sollte für Ihre abgeleiteten Klassen verfügbar sein.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X