2011-03-04 17 views
5

Jeśli utworzyć klasę .NET który subskrybuje do zdarzenia z anonimowej funkcji takich jak to:Czy muszę usunąć ten rodzaj obsługi zdarzeń?

void MyMethod() 
{ 
    Application.Current.Deactivated += (s,e) => { ChangeAppearance(); }; 
} 

Czy ten obsługi zdarzeń być korzeń utrzymując moją klasę przed śmieci zbierane?

Jeśli nie, wohoo! Ale jeśli tak, czy możesz pokazać mi składnię usuwania? Samo użycie - = z tym samym kodem wydaje się błędne.

Odpowiedz

3

Można użyć „prawdziwy” sposób jak sugeruje Simon D., lub zrobić to:

EventHandler handler = null; 
handler = (s,e) => { 
    Application.Current.Deactivated -= handler; 
    ChangeAppearance(); 
}; 
Application.Current.Deactivated += handler; 

Ponieważ jest to dość brzydki i celowość stosowania lambda być succint, I „d prawdopodobnie pójdzie z refaktoryzacją na metodę. Ale warto wiedzieć, co jeszcze działa.

Ostrzeżenie: Jest rzeczą oczywistą, że trzeba być super ultra uważać, aby nie zadzierać z wartością handler w ogóle pomiędzy punktem, gdzie zapisać się na imprezy i miejsca, w którym jest ona rzeczywiście wywołał, w przeciwnym razie część rezygnacji z subskrypcji nie będzie działać poprawnie.

+0

Podoba mi się styl succint tutaj. Dla moich potrzeb powinno to działać idealnie. Dzięki za poświęcenie czasu na napisanie tego! – jschroedl

3

Myślę, że trzeba zrezygnować z subskrypcji, ponieważ dostawca wydarzeń (aplikacja) żyje - lub przynajmniej może żyć - dłużej niż konsument. Każda instancja subskrybująca, która umiera podczas działania aplikacji, spowoduje wycieki pamięci.

Subskrybujesz anonimowego delegata na wydarzenie. Dlatego nie możesz zrezygnować z subskrypcji w ten sam sposób, ponieważ nie możesz już go rozwiązać. Właściwie tworzysz metodę w tym samym momencie, w którym subskrybujesz, i nie przechowujesz żadnego wskaźnika do nowo utworzonej metody.

Jeśli nieznacznie zmienić wdrażanie do korzystania z „prawdziwe” metody, można łatwo zrezygnować z imprezy w taki sam sposób do niej zapisać:

Application.Current.Deactivated += ChangeAppearance; 
Application.Current.Deactivated -= ChangeAppearance; 
private void ChangeAppearance(object sender, EventArgs eventArgs) 
{ 
    throw new NotImplementedException(); 
} 
+0

Dzięki za potwierdzenie podejrzenia. -John – jschroedl

1

to rzeczywiście przeciek, który uniemożliwia zbieranie śmieci. Są na to sposoby - z WeakReference jest jednym z lepszych.

This link ma dobrą rozmowę i dobre odpowiedzi dla Ciebie.

+0

Dzięki za wskaźnik. Ci faceci ładnie to robią !! – jschroedl

2

Zdecydowanie trzeba wyczyścić odniesienie. Jeśli pojawiły się jakiekolwiek wątpliwości, możesz łatwo przetestować swoje własne statyczne wydarzenie, jak na przykład.

static class MemoryLeak 
{ 
    static List<Action<int>> list = new List<Action<int>>(); 
    public static event Action<int> ActivateLeak 
    { 
     add 
     { 
      list.Add(value); 
     } 
     remove 
     { 
      list.Remove(value); 
     } 
    } 
} 

Następnie ustawiając punkt przerwania w funkcji usuwania można zobaczyć, że odniesienie nie jest oczyszczone.

Jako alternatywę dla rozwiązania Simona można użyć drugiego zamknięcia, aby utworzyć akcję "odłączania", która może być przekazywana dookoła.

foo f = new foo(); 
Action<int> callfoo = o => f.bar(); 
MemoryLeak.ActivateLeak += callfoo; 
Action cleanUp =() => MemoryLeak.ActivateLeak -= callfoo; 

// Now you can pass around the cleanUp action and call it when you need to unsubscribe from the event. 
cleanUp(); 
Powiązane problemy