Pergunta

Digamos que temos o seguinte método:

private MyObject foo = new MyObject();

// and later in the class

public void PotentialMemoryLeaker(){
  int firedCount = 0;
  foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);};
  foo.MethodThatFiresAnEvent();
}

Se a classe com este método for instanciada e o PotentialMemoryLeaker método é chamado várias vezes, vazamos memória?

Existe alguma maneira de desengatar esse manipulador de eventos lambda depois que terminarmos de ligar MethodThatFiresAnEvent?

Foi útil?

Solução

Sim, salve-o em uma variável e solte-o.

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); };
foo.AnEvent += evt;
foo.MethodThatFiresAnEvent();
foo.AnEvent -= evt;

E sim, se não o fizer, você vazar memória, pois você conectará um novo objeto delegado a cada vez.Você também notará isso porque cada vez que você chamar esse método, ele despejará no console um número crescente de linhas (não apenas um número crescente, mas para uma chamada para MethodThatFiresAnEvent ele despejará qualquer número de itens, uma vez por cada método anônimo conectado).

Outras dicas

Você não apenas vazará memória, mas também receberá seu lambda chamado várias vezes.Cada chamada de 'PotentialMemoryLeaker' adicionará outra cópia do lambda à lista de eventos, e cada cópia será chamada quando 'AnEvent' for disparado.

Bem, você pode estender o que foi feito aqui para tornar o uso dos delegados mais seguro (sem vazamentos de memória)

Seu exemplo apenas compila para uma classe interna privada chamada de compilador (com campo fireCount e um método nomeado de compilador).Cada chamada para PotentialMemoryLeaker cria uma nova instância da classe de fechamento para a qual where foo mantém uma referência por meio de um delegado para o método único.

Se você não fizer referência a todo o objeto que possui o PotentialMemoryLeaker, tudo isso será coletado como lixo.Caso contrário, você pode definir foo para anular ou esvaziar a lista de manipuladores de eventos de foo escrevendo isto:

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler;

Claro, você precisaria de acesso ao MeuObjeto membros privados da classe.

Sim, da mesma forma que manipuladores de eventos normais podem causar vazamentos.Porque o lambda é realmente alterado para:

someobject.SomeEvent += () => ...;
someobject.SomeEvent += delegate () {
    ...
};

// unhook
Action del = () => ...;
someobject.SomeEvent += del;
someobject.SomeEvent -= del;

Então, basicamente, é apenas uma abreviação do que temos usado no 2.0 todos esses anos.

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