Domanda

Stavo solo leggendo una pagina su eventi su MSDN e Mi sono imbattuto in un frammento di codice di esempio che mi sta sconcertando.

Il codice in questione è questo:

// 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<CustomEventArgs> handler = RaiseCustomEvent;

Comprendo le intenzioni del codice, ma non riesco a vedere come quella particolare riga stia facendo una copia di qualcosa. Tutto ciò che sta facendo è copiare il riferimento ; in realtà non sta eseguendo una copia approfondita dell'istanza delegata. Quindi, a tal fine, in realtà non impedisce affatto le condizioni di gara.

Mi sto perdendo qualcosa di ovvio qui?

È stato utile?

Soluzione

I delegati sono immutabili, quindi si garantisce che il riferimento ottenuto in quel codice non cambi. Se un utente si iscrive o annulla l'iscrizione dopo il controllo null, verrà creato un nuovo delegato e impostato sull'evento. Tuttavia, poiché hai un riferimento a un oggetto completamente diverso e lo invochi, non devi preoccuparti che sia nullo.

Altri suggerimenti

Hai ragione; sta copiando il riferimento.

Tuttavia, i delegati sono immutabili; quando aggiungi un gestore a un evento, viene creato un nuovo delegato che combina i gestori attuali con quello nuovo e viene quindi assegnato al campo.

L'istanza del delegato a cui fa riferimento il campo non può cambiare, quindi evita le condizioni di gara.

Eric Lippert lo ha già trattato in un post .

Anche questo è da MSDN ..

" L'elenco di invocazione di un delegato è un insieme ordinato di delegati in cui ciascun elemento dell'elenco invoca esattamente uno dei metodi rappresentati dal delegato. Un elenco di invocazioni può contenere metodi duplicati. Durante una chiamata, i metodi vengono richiamati nell'ordine in cui compaiono nell'elenco di chiamata. Un delegato tenta di invocare tutti i metodi nel suo elenco di invocazioni; i duplicati vengono invocati una volta per ogni volta che compaiono nell'elenco di invocazione. I delegati sono immutabili; una volta creato, l'elenco di invocazione di un delegato non cambia. "

if (qualunque cosa! = null) qualunque (); sembra che assicuri che qualunque non sia mai nullo quando si chiama qualunque () , ma in realtà non lo garantisce in uno scenario thread. Un thread diverso può impostare qualunque = null tra il controllo e la chiamata.

Foo temp = whatever;
if (temp != null) temp();

Questo codice rimuove la possibilità della null dereference, poiché temp è un locale e pertanto non verrà mai modificato da un thread diverso. Quindi impedisce una condizione di gara. Tuttavia, non impedisce tutte le condizioni di gara pertinenti. Eric Lippert ha fatto un discussione più elaborata di alcuni altri problemi con il codice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top