Question

J'ai une classe de base DockedToolWindow: forme, et de nombreuses classes qui dérivent de DockedToolWindow. J'ai une classe de conteneur qui détient et attribue les événements à DockedToolWindow objets, mais je veux invoquer les événements de la classe enfant.

J'ai une question sur la façon de mettre en œuvre ce que cette le site MSDN me dit de faire. Cette section ci-dessous me donne le problème:

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

Bien sûr, cet exemple compile et fonctionne, mais quand je remplace « ShapeChanged » avec « Move » (un événement que j'acquis de tirer du formulaire), il des erreurs disant que je ne peux pas avoir déplacer sur le côté droit sans + = ou - =. J'ai aussi enlevé les balises génériques ShapeEventArgs.

Toute incitation pourquoi cela ne fonctionne pas? Quelle est la différence entre un événement déclaré dans la classe et qui est héritée?

Était-ce utile?

La solution

Vous ne pouvez pas tirer directement des événements de classe de base. C'est exactement la raison pour laquelle vous avez dû faire votre méthode OnShapeChanged protected au lieu de private.

Utilisez base.OnMove () au lieu.

Autres conseils

A partir de la spécification du langage C #, l'article 10.7 (italique ajouté):

  

Dans le texte du programme de la classe ou struct qui contient la déclaration d'un événement, certains événements peuvent être utilisés comme champs . A utiliser de cette manière, un événement ne doit pas être abstraite ou externe, et ne doit pas inclure explicitement les déclarations-accesseurs-événement. Un tel événement peut être utilisé dans un contexte qui permet un champ. Le champ contient un délégué (§15) qui fait référence à la liste des gestionnaires d'événements qui ont été ajoutés à l'événement. Si aucun gestionnaire d'événements ont été ajoutés, le champ contient nulle.

Ainsi, la raison pour laquelle vous ne pouvez pas traiter l'événement Move comme un champ est qu'il est défini dans un autre type (dans ce cas, votre superclasse). Je suis d'accord avec la spéculation @ womp que les concepteurs ont fait ce choix pour éviter Monkeying involontaire avec l'événement. Il semble de toute évidence mauvaise pour permettre types non apparentés (types non dérivés du type déclarant l'événement) pour ce faire, mais même pour les types dérivés, il pourrait ne pas être souhaitable. Ils auraient probablement dû inclure la syntaxe pour permettre la déclaration d'événement à être private ou protected par rapport à l'utilisation de style champ, donc je suppose qu'ils ont choisi de désavouer tout entièrement.

La différence est portée. A l'intérieur de votre classe, vous pouvez contrôler la façon dont vos délégués d'événements sont traités, cependant, votre classe ne peut pas contrôler ce que la classe de base est en train de faire. Il pourrait faire un peu fou choses derrière les coulisses de l'événement et de ses gestionnaires. Si vous simplement « réaffecté » l'événement Move, vous seriez Anéantir la liste des délégués de multidiffusion pour l'événement.

Je devine qu'ils ont mis une restriction du compilateur sur ce point car sa pratique très dangereuse, et aurait essentiellement pour donner une classe descendant la capacité de détruire le modèle d'événement de son parent.

Vous avez seulement besoin du code affiché dans la classe où l'événement lui-même est défini. Toutes les classes dérivées doivent simplement appeler OnShapeChanged () ou OnMove () directement, sans la copie, etc., donc vous ne devriez pas être écrire que le code du tout dans vos classes (depuis l'événement de déplacement est défini dans la base).

Si vous avez besoin de faire une sorte de traitement dans la classe dérivée (vous devez peut-être jouer avec votre classe de collection?), Vous substituez l'appel OnXXX virtuel et vous farcir avant d'appeler base.OnXXX (). Dans l'article MSDN, la classe Circle correspond à votre classe DockedToolWindow. Le même schéma devrait être disponible pour vos classes dérivées.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top