2012-04-23 7 views
12

maggior parte del codice che ho visto utilizza il seguente modo di dichiarare e richiamare cottura evento:È un modo migliore per attivare/invocare eventi senza un controllo Null in C#?

public class MyExample 
{ 
    public event Action MyEvent; // could be an event EventHandler<EventArgs>, too 

    private void OnMyEvent() 
    { 
     var handler = this.MyEvent; // copy before access (to aviod race cond.) 
     if (handler != null) 
     { 
      handler(); 
     } 
    } 

    public void DoSomeThingsAndFireEvent() 
    { 
     // ... doing some things here 
     OnMyEvent(); 
    } 
} 

Anche ReSharper genera un metodo invocante il modo di cui sopra.

Perché non basta fare in questo modo:

public class MyExample 
{ 
    public event Action MyEvent = delegate {}; // init here, so it's never null 

    public void DoSomeThingsAndFireEvent() 
    { 
     // ... doing some things here 
     OnMyEvent(); // save to call directly because this can't be null 
    } 
} 

Qualcuno può spiegare un motivo per cui non fare questo? (pro vs. contro)

+0

Ho sentito che Jon Skeet fa entrambe le cose ... –

+0

Penso che nella maggior parte dei casi non è importante farsi notare se c'è almeno un ascoltatore "reale" collegato ... come visto sopra c'è già un controllo nullo se usato in modo "normale". – Beachwalker

+0

possibile duplicato di [C'è un lato negativo nell'aggiunta di un delegato vuoto anonimo sulla dichiarazione di eventi?] (Http://stackoverflow.com/questions/170907/is-there-a-downside-to-adding-an-anonymous-empty -delegate-on-event-declaration) – CodesInChaos

risposta

16

I pro ei contro sono:

  • controlli nulli sono estremamente a buon mercato; stiamo parlando di miliardesimi di secondo. L'allocazione di un delegato e la raccolta dei dati inutilmente per il resto della durata dell'oggetto potrebbero richiedere all'incirca alcuni milionesimi di di un secondo. Inoltre, stai consumando dozzine di byte di memoria. Inoltre, ogni volta che l'evento si attiva, ottieni una chiamata non necessaria a un metodo che non fa nulla, consumando ancora più microsecondi. Se sei il tipo di persona a cui importa circa milionesimi di secondo e dozzine di byte, quella potrebbe essere una differenza significativa; per la stragrande maggioranza dei casi non lo farà.

  • È necessario ricordare di creare sempre il delegato vuoto. È davvero più facile che ricordarsi di verificare la nullità?

  • Nessuno dei due motivi rende effettivamente l'evento sicuro. È ancora del tutto possibile con entrambi i pattern che un gestore di eventi venga sparato su un thread mentre viene rimosso su un altro thread, e ciò significa che corrono. Se il codice di rimozione del gestore distrugge lo stato richiesto dal gestore, è possibile che un thread stia distruggendo quello stato mentre un altro thread sta eseguendo il gestore. Non pensare che il semplice controllo di null o l'assegnazione di un handler vuoto elimini magicamente le condizioni di gara. Elimina solo la condizione di competizione che risulta nel dereferenziamento null.

+3

Non solo l'aggiunta di un gestore vuoto spreca memoria nel caso in cui non venga utilizzato alcun gestore, ma soprattutto rende l'aggiunta e la rimozione del primo vero handler * molto * più costoso. Aggiungere il primo handler a un evento è molto economico: basta sostituire il null con il gestore. Rimuovere l'unico gestore da un evento è economico: sostituirlo con null. Tutti gli altri casi sono molto più costosi in confronto. – supercat

+0

Sì, un controllo nulla è veloce ma non è la copia del gestore prima del controllo di un'operazione costosa? È fatto con ogni evento che spara chiamando OnMyEvent(). Vedi codice var handler = this.MyEvent; (nell'esempio) Sono disponibili comparazioni pratiche di "vita reale"? – Beachwalker

+1

@Stegi: la copia è completamente gratuita. Una volta caricato nel registro, viene semplicemente tenuto lì. (Almeno nel codice ottimizzato) – configurator

5

E può essere nullo. Considerare:

var x = new MyExample(); 
    x.MyEvent += SomeHandler; 

    // ... later, when the above code is disposed of 

    x.MyEvent -= SomeHandler; 

EDIT: in realtà, io lo prendo indietro. Dopo aver provato questo, se hai usato un delegato anonimo per impostare il gestore, non sembra che tu possa scaricare , così puoi salvare il controllo null.

non sono sicuro se questo è un comportamento affidabile, però, o solo un artefatto della implementazione del linguaggio ...

6

è una cosa stile di sicuro; tuttavia, penso che molti sviluppatori vadano per la sicurezza con stile quando si tratta di controlli nulli. Non c'è niente in questo mondo che possa garantire che un bug non si insinui nel sistema e che il controllo nullo continui a non essere necessario.