Frage

Sagen wir, wir haben die folgende Methode:

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();
}

Wenn die Klasse, die mit dieser Methode instanziiert wird und die PotentialMemoryLeaker Methode mehrfach aufgerufen wird, haben wir ein Speicherleck?

Gibt es irgendeine Art und Weise zu lösen, die lambda-Ereignis-handler, nachdem wir fertig aufrufen MethodThatFiresAnEvent?

War es hilfreich?

Lösung

Ja, speichern Sie es einer Variablen zu, und lösen Sie es.

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

Und ja, wenn Sie das nicht tun, werden Sie Leck Speicher, wie Sie hook up einen neuen Delegaten-Objekt jedes mal.Sie werden auch bemerken dies, weil jedes mal, wenn Sie diese Methode aufrufen, es werden-dump auf die Konsole eine zunehmende Anzahl von Zeilen (und nicht nur eine Zahl, aber für einen Aufruf MethodThatFiresAnEvent es wird dump eine beliebige Anzahl von Elementen, einmal für jede hooked up anonyme Methode).

Andere Tipps

Sie werden nicht nur ein Speicherleck, werden Sie auch Ihre lambda-Funktion für mehrere mal.Jeder Aufruf von 'PotentialMemoryLeaker' wird eine weitere Kopie hinzufügen der lambda-auf die event-Liste, und jede Kopie wird aufgerufen, wenn 'AnEvent' ausgelöst wird.

Auch können Sie verlängern, was getan wurde hier machen Delegierten sicherer zu verwenden (keine Speicherverluste)

Ihr Beispiel nur kompiliert zu einem compiler-namens private innere Klasse (mit Feld firedCount und eine compiler-Namen-Methode).Bei jedem Aufruf PotentialMemoryLeaker erstellt eine neue Instanz der Schließung Klasse, wo foo behält einen Verweis durch einen Delegaten, der einzigen Methode.

Wenn Sie nicht das ganze Objekt, das Eigentümer PotentialMemoryLeaker, dann werden alle Müll gesammelt.Andernfalls können Sie entweder foo zu null oder leer foo event-handler-Liste durch das schreiben dieses:

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

Natürlich, Sie würde benötigen Zugriff auf die MyObject Klasse an der privaten Mitglieder.

Ja, in der gleichen Weise, dass die normalen Ereignis-Handler kann zu Undichtigkeiten führen.Da der lambda-Ausdruck ist eigentlich geändert:

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

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

Also im Grunde ist es einfach nur kurzer hand für das, was wir verwenden in 2.0 haben alle diese Jahre.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top