Pergunta

Eu estava apenas lendo uma página em eventos No MSDN, e eu me deparei com um trecho de código de exemplo que está me intrigando.

O código em questão é o seguinte:

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

Entendo as intenções do código, mas não vejo como essa linha específica está fazendo uma cópia de qualquer coisa. Tudo o que está fazendo é copiar o referência; Na verdade, não está fazendo uma cópia profunda da instância delegada. Então, para esse fim, na verdade não impede a condição de corrida.

Estou perdendo algo óbvio aqui?

Foi útil?

Solução

Os delegados são imutáveis; portanto, a referência obtida nesse código é garantida para não alterar. Se um usuário assinar ou cancelar inscrição após a verificação nula, um novo delegado será criado e definido para o evento. No entanto, como você tem uma referência a um objeto completamente diferente e invoca isso, você não precisa se preocupar em ser nulo.

Outras dicas

Você está certo; está copiando a referência.

No entanto, os delegados são imutáveis; Quando você adiciona um manipulador a um evento, um novo delegado é criado, combinando o (s) manipulador (s) atual (s) com o novo e é atribuído ao campo.

A instância delegada de que o campo está referenciando não pode mudar, por isso evita a condição de corrida.

Eric Lippert já cobriu isso em um muito detalhado publicar.

Isso é do msdn também ..

"A lista de invocação de um delegado é um conjunto ordenado de delegados nos quais cada elemento do A lista chama exatamente um dos métodos representados pelo delegado. Uma lista de invocação pode conter métodos duplicados. Durante uma invocação, os métodos são chamados na ordem em que aparecem na lista de invocação. Um delegado tenta invocar todos os métodos em sua lista de invocação; As duplicatas são chamadas uma vez para cada vez que aparecerem na lista de invocação. Os delegados são imutáveis; Uma vez criado, a lista de invocação de um delegado não muda."

if (whatever != null) whatever(); Parece que garante que whatever nunca é nulo quando whatever() é chamado, mas na verdade não garante que em um cenário encadeado. Um fio diferente pode definir whatever = null entre o cheque e a chamada.

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

Este código remove a possibilidade da desreferência nula, já que temp é um local e, portanto, nunca será modificado por um encadeamento diferente. Portanto, evita uma condição de corrida. No entanto, isso não impede todas as condições relevantes da raça. Eric Lippert fez um mais elaborado discussão de alguns outros problemas com o código.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top