2009-04-23 15 views
8

Tengo una clase base DockedToolWindow: Form y muchas clases que se derivan de DockedToolWindow. Tengo una clase contenedora que contiene y asigna eventos a objetos DockedToolWindow, sin embargo, deseo invocar los eventos desde la clase secundaria.Levantar eventos de clase base en clases derivadas C#

De hecho, tengo una pregunta sobre cómo implementar lo que este MSDN site me dice que haga. Esta sección de abajo me está dando el problema:

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

Claro este ejemplo compila y funciona, pero cuando sustituyo "ShapeChanged" con "Move" (un evento que adquirí desde que deriva de la Forma), él los errores diciendo que no puedo tener Move en el lado derecho sin + = o - =. También eliminé las etiquetas genéricas ShapeEventArgs.

¿Alguna incitación sobre por qué esto no está funcionando? ¿Cuál es la diferencia entre un evento declarado dentro de la clase y uno que se hereda?

Respuesta

12

No puede disparar directamente los eventos de la clase base.Esta es exactamente la razón por la que tuvo que hacer que su método OnShapeChangedprotected en lugar de private.

Use base.OnMove() en su lugar.

+0

Veo que OnMove() resolvería esto, sin embargo, ¿cómo no puedo invocar la explicidad de OnMove() cuando es necesario? No sé dónde se llama realmente el marco al delegado Move, y probablemente esté oculto para mí de todos modos. – Balk

+3

OnMove activa el evento Mover, del mismo modo que OnShapeChanged activa el evento ShapeChanged en su código. Es un patrón común agregar miembros protegidos que desencadenan eventos para que sean visibles para las clases derivadas. En ese caso, el prefijo "Encendido" generalmente se agrega (OnMove, OnClick, etc.) – Groo

+0

Para ver dónde el marco realmente dispara el evento Move, use la herramienta Reflector (http://www.red-gate.com/products/reflector /) para obtener el código fuente para el método Form.OnMove. – Groo

3

La diferencia es el alcance. Dentro de su clase, puede controlar cómo se manejan los delegados de su evento, sin embargo, su clase no puede controlar lo que está haciendo la clase base. Podría estar haciendo cosas alocadas detrás de escena con el evento y sus manipuladores. Si simplemente "reasignaste" el evento Move, estarás borrando la lista de delegados de multidifusión para el evento.

Supongo que ponen una restricción de compilación en esto porque es una práctica muy insegura, y esencialmente le daría a cualquier clase descendiente la capacidad de destruir el modelo de evento de su padre.

4

De la especificación del lenguaje C#, sección 10.7 (énfasis añadido):

Dentro del texto del programa de la clase o estructura que contiene la declaración de un evento, ciertos eventos se puede utilizar como campos. Para ser utilizado de esta manera, un evento no debe ser abstracto o externo, y no debe incluir explícitamente declaraciones de acceso a eventos. Tal evento se puede usar en cualquier contexto que permita un campo. El campo contiene un delegado (§15) que hace referencia a la lista de controladores de eventos que se han agregado al evento. Si no se agregaron controladores de eventos, el campo contiene null.

Por lo tanto, la razón por la que no se puede tratar el evento Move como un campo es que se define en un tipo diferente (en este caso, su superclase). Estoy de acuerdo con la especulación de @ womp de que los diseñadores tomaron esta decisión para evitar el monkeying involuntario con el evento. Parece obviamente malo permitir que tipos no relacionados (tipos no derivados del tipo que declara el evento) hagan esto, pero incluso para los tipos derivados, puede que no sea deseable. Probablemente tendrían que haber incluido la sintaxis para permitir que la declaración del evento se haga private o protected con respecto al uso de estilo de campo, así que supongo que optaron por simplemente no permitirlo.

1

Solo necesita el código que ha publicado en la clase donde está definido el evento en sí. Todas las clases derivadas deberían simplemente llamar a OnShapeChanged() o OnMove() directamente, sin copiar, etc., por lo que no debería escribir ese código en absoluto en sus clases (ya que el evento Move está definido en la base).

Si necesita hacer algún tipo de procesamiento en la clase derivada (¿tal vez necesita manipular su clase de colección?), Anula la llamada virtual OnXXX y hace las cosas antes de llamar a base.OnXXX(). En el artículo de MSDN, la clase Circle corresponde a su clase DockedToolWindow. El mismo patrón debe estar disponible para sus clases derivadas.

+0

Veo que OnMove() resolvería esto, pero ¿cómo no puedo invocar la explicidad de OnMove() cuando es necesario? No sé dónde se llama realmente el marco al delegado Move, y probablemente esté oculto para mí de todos modos. – Balk

Cuestiones relacionadas