Pregunta

Estaba leyendo una página sobre eventos en MSDN, y Me encontré con un fragmento de código de ejemplo que me está desconcertando.

El código en cuestión es este:

// 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;

Entiendo las intenciones del código, pero no veo cómo esa línea en particular está haciendo una copia de algo. Todo lo que está haciendo es copiar la referencia ; en realidad no está haciendo una copia profunda de la instancia de delegado. Entonces, para ese fin, en realidad no previene la condición de carrera en absoluto.

¿Me estoy perdiendo algo obvio aquí?

¿Fue útil?

Solución

Los delegados son inmutables, por lo que se garantiza que la referencia obtenida en ese código no cambiará. Si un usuario se suscribe o se da de baja después de la verificación nula, se creará un nuevo delegado y se configurará para el evento. Sin embargo, dado que tiene una referencia a un objeto completamente diferente e invoca eso, no tiene que preocuparse de que sea nulo.

Otros consejos

Tienes razón; está copiando la referencia.

Sin embargo, los delegados son inmutables; cuando agrega un controlador a un evento, se crea un nuevo delegado, que combina los controladores actuales con el nuevo, y luego se asigna al campo.

La instancia de Delegado a la que hace referencia el campo no puede cambiar, por lo que evita la condición de carrera.

Eric Lippert ya cubrió esto en un muy detallado post .

Esto también es de MSDN ..

" La lista de invocación de un delegado es un conjunto ordenado de delegados en el que cada elemento de la lista invoca exactamente uno de los métodos representados por el delegado. Una lista de invocación puede contener métodos duplicados. Durante una invocación, los métodos se invocan en el orden en que aparecen en la lista de invocación. Un delegado intenta invocar cada método en su lista de invocación; Los duplicados se invocan una vez por cada vez que aparecen en la lista de invocación. Los delegados son inmutables; una vez creada, la lista de invocación de un delegado no cambia. "

if (whatever! = null) whatever (); parece que asegura que whatever nunca es nulo cuando se llama a whatever () , pero en realidad no garantiza eso en un escenario roscado. Un hilo diferente puede establecer whatever = null entre el cheque y la llamada.

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

Este código elimina la posibilidad de la anulación de referencia, ya que temp es un local y, por lo tanto, nunca será modificado por un hilo diferente. Por lo tanto, evita una condición de carrera. Sin embargo, no evita todas las condiciones de carrera relevantes. Eric Lippert hizo un discusión más elaborada sobre algunos otros problemas con el código.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top