2010-10-15 9 views
25

Considerando il codice qui sotto:invocazione di un campo simile polimorfico evento

public class TableMain { 
    public virtual event Action UpdateFilter; 
    .... 
} 

public class TableSub : TableMain { 
    public override event Action UpdateFilter; 

    public void UpdateQuery() { 
     ..... 
     if (UpdateFilter!=null) { 
       UpdateFilter(); // Invocation of polymorphic field-like event??? 
     } 
    } 
} 

In questo codice ReSharper mostra la segnalazione "invocazione polimorfico evento campo-like".

La mia domanda è: Che cosa significa in realtà? Ed è un avviso per una cattiva pratica di programmazione? Inoltre, è una cattiva pratica chiamare polimorficamente un evento? (Sapendo che un evento può essere sollevato solo dalla classe che lo ha dichiarato.)

risposta

41

Bene, hai effettivamente due eventi simili a campi qui. L'override sovrascrive la parte aggiungi/rimuovi, ma avrai due campi: uno in TableMain e uno in TableSub. Solo quello in TableSub sarà mai non nullo, a meno che il valore sia impostato esplicitamente in TableMain ... quindi se TableMain tenta di generare l'evento stesso, non chiamerà lo stesso insieme di gestori come in TableSub. Fondamentalmente, si sta comportando in modo strano.

L'approccio giusto è quello di fornire un metodo protetto in TableMain per consentire l'evento per essere sollevata da sottoclassi:

protected void OnUpdateFilter() 
{ 
    Action handler = UpdateFilter; 
    if (handler != null) 
    { 
     handler(); 
    } 
} 

Poi rendere l'evento non virtuale, e rimuovere l'override in TableSub.

Si noti che la firma dell'evento non corrisponde alla normale convenzione per gli eventi, nessun motivo per non utilizzare EventHandler?

+0

Questa mi sembra una grande fonte di errore potenziale, perché molto probabilmente non è ciò che ci si aspetterebbe quando si scrive tale codice. Non ho mai avuto la necessità di pensare a quell'aspetto specifico prima. Sai perché gli eventi virtuali sono sintatticamente ammessi in ogni caso? –

+1

@ John. Riguardo --- "Si noti che la firma dell'evento non corrisponde alla normale convenzione per gli eventi - qualsiasi motivo per non utilizzare EventHandler?" Sto solo facendo uso del delegato "Azione" esistente, poiché in questo caso non ho bisogno di argomenti (oggetto, eventargs) negli iscritti a questo evento. È (di nuovo) una cattiva pratica di programmazione? È un'idea migliore creare un delegato separato (vuoto) per questo caso? –

+1

@Thomas: Esistono modi in cui * è possibile * utilizzarli in modo ragionevole, ad esempio, è possibile registrare ogni abbonamento e quindi trasferirlo all'implementazione di base. Inoltre è necessario essere in grado di avere eventi astratti efficaci per poterli inserire nelle interfacce. –