2009-04-23 16 views
8

Ho una classe base DockedToolWindow: Form e molte classi che derivano da DockedToolWindow. Ho una classe contenitore che conserva e assegna gli eventi agli oggetti DockedToolWindow, tuttavia desidero richiamare gli eventi dalla classe figlio.Evento eventi di classe base in classi derivate C#

In realtà ho una domanda su come implementare ciò che questo MSDN site mi sta dicendo di fare. Questa sezione sotto di me sta dando il 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); 
     } 
    } 

Certo questo esempio compila e funziona, ma quando sostituisco "ShapeChanged" con "Move" (un evento che ho acquisito da derivante da Form), esso errori dicendo che non posso avere Move sul lato destro senza + = o - =. Ho rimosso anche i tag generici di ShapeEventArgs.

Qualche istigazione sul perché questo non funziona? Qual è la differenza tra un evento dichiarato all'interno della classe e uno ereditato?

risposta

12

Non è possibile attivare direttamente eventi di classe base.Questo è esattamente il motivo per cui hai dovuto creare il tuo metodo anziché private.

Utilizzare invece base.OnMove().

+0

Vedo che OnMove() risolverebbe questo, tuttavia, come non può richiamare OnMove() in modo esplicito quando è necessario, posso? Non so dove il framework in realtà chiami il delegato di Move, ed è probabilmente nascosto da me comunque. – Balk

+3

OnMove lancia l'evento Move, nello stesso modo in cui OnShapeChanged attiva l'evento ShapeChanged nel codice. È uno schema comune per aggiungere membri protetti che generano eventi, per renderli visibili alle classi derivate. In tal caso, viene generalmente aggiunto il prefisso "On" (OnMove, OnClick, ecc.) – Groo

+0

Per vedere dove il framework attiva l'evento Move, utilizzare lo strumento Reflector (http://www.red-gate.com/products/reflector /) per ottenere il codice sorgente per il metodo Form.OnMove. – Groo

3

La differenza è lo scopo. All'interno della classe, puoi controllare come vengono gestiti i delegati dell'evento, tuttavia, la tua classe non può controllare ciò che sta facendo la classe base. Potrebbe essere qualcosa di pazzesco dietro le quinte con l'evento e i suoi gestori. Se hai semplicemente "riassegnato" l'evento Move, cancelleresti l'elenco dei delegati multicast per l'evento.

Immagino che abbiano imposto una limitazione del compilatore su questo perché è una pratica molto poco sicura e sostanzialmente darebbe a qualsiasi classe discendente la possibilità di distruggere il modello di evento del suo genitore.

4

Dal linguaggio C# spec, sezione 10.7 (enfasi aggiunta):

All'interno del testo programma della classe o struct che contiene la dichiarazione di un evento, alcuni eventi possono essere usati come campi. Per essere utilizzato in questo modo, un evento non deve essere astratto o extern e non deve includere esplicitamente le dichiarazioni di accesso agli eventi. Tale evento può essere utilizzato in qualsiasi contesto che consente un campo. Il campo contiene un delegato (§15) che fa riferimento all'elenco di gestori di eventi che sono stati aggiunti all'evento. Se non sono stati aggiunti gestori di eventi, il campo contiene null.

Pertanto, il motivo per cui non è possibile considerare l'evento Move come un campo è che è definito in un tipo diverso (in questo caso, la superclasse). Sono d'accordo con la speculazione di @ womp che i progettisti hanno fatto questa scelta per prevenire la monkeying involontaria con l'evento. Sembra ovviamente negativo consentire tipi non correlati (tipi non derivati ​​dal tipo che dichiara l'evento) per farlo, ma anche per i tipi derivati, potrebbe non essere desiderabile. Probabilmente avrebbero dovuto includere la sintassi per consentire la dichiarazione degli eventi da effettuare private o protected rispetto all'utilizzo in stile campo, quindi la mia ipotesi è che abbiano scelto di disattivarlo completamente.

1

Hai solo bisogno del codice che hai postato nella classe in cui è definito l'evento stesso. Tutte le classi derivate dovrebbero semplicemente chiamare OnShapeChanged() o OnMove() direttamente, senza copiare, ecc., Quindi non dovresti scrivere quel codice affatto nelle tue classi (poiché l'evento Move è definito nella base).

Se è necessario eseguire qualche tipo di elaborazione nella classe derivata (forse è necessario giocare con la classe di raccolta?), Si esegue l'override della chiamata OnXXX virtuale e si fanno prima di chiamare la base.OnXXX(). Nell'articolo MSDN, la classe Circle corrisponde alla classe DockedToolWindow. Lo stesso modello dovrebbe essere disponibile per le classi derivate.

+0

Vedo che OnMove() risolverebbe questo, tuttavia, come non può richiamare OnMove() in modo esplicito quando è necessario, posso? Non so dove il framework in realtà chiami il delegato di Move, ed è probabilmente nascosto da me comunque. – Balk

Problemi correlati