2009-07-14 14 views
18

Come funziona un evento virtuale? Come lo ignoreresti? Come funzionerebbe? E in quali casi lo faresti?C#: quali sono gli eventi virtuali e come possono essere utilizzati?

Sarebbe, ad esempio, un sostituto ok per i metodi OnEvent protetti? In modo che le classi ereditanti possano semplicemente scavalcare l'evento e sollevarlo direttamente? O sarebbe sbagliato o semplicemente non funziona?

MSDN dice a questo proposito:

Un evento può essere contrassegnato come un evento virtuale utilizzando la parola chiave virtuale. Ciò consente alle classi derivate di sovrascrivere il comportamento dell'evento utilizzando la parola chiave override. Un evento che sovrascrive un evento virtuale può anche essere sigillato, il che specifica che per le classi derivate non è più virtuale.

Ma questo non mi ha reso molto più saggio. La roba sigillata è ovvia però.

Nota: ho visto la questione How virtual events work in C# ?, ma non era veramente come funzionano eventi virtuali. Piuttosto è stato il modo in cui quella persona ha ottenuto il risultato ottenuto dall'usarli. Ho cercato di capire quali erano gli eventi virtuali dal suo esempio e le risposte, ma non poteva davvero dare un senso a questo.

+0

Articolo "Eventi virtuali in C#: qualcosa è andato storto" - http://www.viva64.com/en/b/0453/ –

risposta

23

Un evento virtuale è semplicemente uno che può essere sovrascritto in una classe derivata.

Sei contento del concetto di una proprietà virtuale, con getter e setter che possono essere ignorati? Se è così, puoi pensare ad un evento virtuale esattamente nello stesso modo: invece di un getter e setter, c'è un'operazione "aggiungi" e un'operazione "rimuovi". Questi possono essere virtuali, quindi gestiti in modo polimorfico. Li implementate nello stesso modo in cui implementate qualsiasi altro membro virtuale/sottoposto a override.

Esempio:

using System; 

class Base 
{ 
    public virtual event EventHandler Foo 
    { 
     add 
     { 
      Console.WriteLine("Base Foo.add called"); 
     } 
     remove 
     { 
      Console.WriteLine("Base Foo.remove called"); 
     } 
    } 
} 

class Derived : Base 
{ 
    public override event EventHandler Foo 
    { 
     add 
     { 
      Console.WriteLine("Derived Foo.add called"); 
     } 
     remove 
     { 
      Console.WriteLine("Derived Foo.remove called"); 
     } 
    } 
} 

class Test 
{ 
    static void Main() 
    { 
     Base x = new Derived(); 

     x.Foo += (sender, args) => {}; 
    } 
} 

Si noti che l'evento in sé non è responsabile di ciò che accade quando si è sollevato - solo l'aggiunta/rimozione lato. (In C#, comunque, lo stesso CLR ha la nozione di raise, ma per il momento lo ignoreremo.)

Si potrebbe anche voler leggere my article on events se si è leggermente confusi sulla differenza tra un evento e un delegato.

Personalmente lo trovo molto raro che voglio un evento virtuale.

+0

Se la classe genitore solleva l'evento sottoposto a override, sarebbe comunque lo stesso evento, giusto ? Quindi se tu avessi 'classe A' e' classe A: B', gli abbonati si iscriverebbero allo stesso evento di un oggetto sia se fosse fatto come A o come B? – Svish

+1

Il non innalzamento è completamente separato. Se la classe A sovrascrive l'add/remove e non richiama l'add/remove della classe B, allora viene chiamato il meccanismo di classe B per la generazione dell'evento, quindi non viene chiamato nessuno dei gestori.Pensa a tutto in termini di metodi semplici: l'evento fornisce add/remove che può essere virtuale, ma non specifica nulla sulla semantica di innalzamento dell'evento. –

+0

Quindi, affinché funzioni correttamente, dovresti fare base.add e base.remove o qualcosa del genere? (Se esiste ...) – Svish

0

Si noti inoltre che in C# una classe derivata non è in grado di attivare l'evento puramente definito nella classe base (indipendentemente dal modificatore). Quindi, o abbiamo bisogno di avere un evento nuovo o di sovrascrittura per la classe derivata e nella maggior parte dei casi è preferibile uno override se lo stesso evento è destinato a essere licenziato.

+0

Ma questo può essere facilmente risolto creando un metodo 'protetto Raise ...' nella classe base e chiamandolo dalla classe derivata. – MarioDS

Problemi correlati