Domanda

Supponiamo di avere il seguente metodo:

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 la classe con questo metodo viene istanziata e il file PotentialMemoryLeaker viene chiamato più volte, perdiamo memoria?

Esiste un modo per sganciare il gestore di eventi lambda dopo aver finito di chiamare MethodThatFiresAnEvent?

È stato utile?

Soluzione

Sì, salvalo in una variabile e sgancialo.

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

E sì, se non lo fai, lo farai perdere memory, poiché collegherai ogni volta un nuovo oggetto delegato.Lo noterai anche perché ogni volta che chiami questo metodo, scaricherà sulla console un numero crescente di righe (non solo un numero crescente, ma per una chiamata a MethodThatFiresAnEvent scaricherà un numero qualsiasi di elementi, una volta per ciascuno collegato metodo anonimo).

Altri suggerimenti

Non solo perderai memoria, ma la tua lambda verrà anche chiamata più volte.Ogni chiamata di "PotentialMemoryLeaker" aggiungerà un'altra copia di lambda all'elenco degli eventi e ogni copia verrà chiamata quando viene attivato "AnEvent".

Bene, puoi estendere ciò che è stato fatto Qui per rendere i delegati più sicuri da usare (nessuna perdita di memoria)

Il tuo esempio viene semplicemente compilato in una classe interna privata denominata dal compilatore (con il campo firedCount e un metodo denominato dal compilatore).Ogni chiamata a PotentialMemoryLeaker crea una nuova istanza della classe di chiusura alla quale dove foo mantiene un riferimento tramite un delegato al singolo metodo.

Se non fai riferimento all'intero oggetto che possiede PotentialMemoryLeaker, tutto verrà raccolto in modo spazzatura.Altrimenti puoi impostare pippo per null o svuotare l'elenco dei gestori di eventi di foo scrivendo questo:

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

Naturalmente, avresti bisogno dell'accesso a Il miooggetto membri privati ​​della classe.

Sì, nello stesso modo in cui i normali gestori di eventi possono causare perdite.Perché la lambda è effettivamente cambiata in:

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

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

Quindi in pratica è solo una scorciatoia per ciò che abbiamo utilizzato nel 2.0 in tutti questi anni.

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