Pregunta

Tengo una clase base DockedToolWindow: Form y muchas clases que se derivan de DockedToolWindow. Tengo una clase de contenedores que posee y asigna eventos a los objetos DockedToolWindow, sin embargo, quiero invocar los eventos de la clase infantil.

De hecho, tengo una pregunta sobre cómo implementar qué Sitio MSDN me dice que lo haga. Esta sección a continuación 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 que este ejemplo compila y funciona, pero cuando reemplazo "ShapeChanged" con "Move" (un evento que adquirí derivado de la forma), errora que no puedo moverme en el lado derecho sin += o -=. También quité las etiquetas genéricas de ShapeeVentArgs.

¿Alguna incitación sobre por qué esto no funciona? ¿Cuál es la diferencia entre un evento declarado dentro de la clase y uno heredado?

¿Fue útil?

Solución

No puedes disparar directamente los eventos de la clase base. Esta es exactamente la razón por la que tenía que hacer su OnShapeChanged método protected en vez de private.

Usar base.onmove () en cambio.

Otros consejos

De la especificación del lenguaje C#, Sección 10.7 (énfasis agregado):

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

Por lo tanto, la razón por la que no puede tratar el evento de movimiento como un campo es que se define en un tipo diferente (en este caso, su superclase). Estoy de acuerdo con la especulación de @wompes de que los diseñadores tomaron esta decisión para evitar que el monucio involuntario con el evento. Obviamente, parece malo permitir tipos no relacionados (tipos no derivados del tipo que declara el evento) para hacer esto, pero incluso para los tipos derivados, podría no ser deseable. Probablemente habrían tenido que incluir la sintaxis para permitir que se realice la declaración del evento. private o protected Con respecto al uso de estilo campo, entonces supongo que optaron por no permitirlo por completo.

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

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

Solo necesita el código que publicó en la clase donde se define el evento en sí. Todas las clases derivadas simplemente deben llamar a OnshapeChanged () o onMove () directamente, sin la copia, etc., por lo que no debe escribir ese código en sus clases (ya que el evento de movimiento se define en la base).

Si necesita hacer algún tipo de procesamiento en la clase derivada (¿tal vez necesite jugar con su clase de recolección?), Anula la llamada virtual de ONXXX y lo hace 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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top