2009-09-01 19 views
187

Możliwe duplikaty:
Unsubscribe anonymous method in C#
How do I Unregister ‘anonymous’ event handlerJak usunąć obsługi zdarzeń lambda

Niedawno odkryto, że można używać do tworzenia prostych lambdy obsługi zdarzeń. Mogę na przykład zasubskrybować takie wydarzenie typu kliknięcia:

button.Click += (s, e) => MessageBox.Show("Woho"); 

Ale w jaki sposób zrezygnowałbyś z subskrypcji?

+0

Zobacz tutaj: http://stackoverflow.com/questions/183367 –

+0

Czy próbowałeś operatora - =? – Maciek

+1

@Svish: lambda jest zasadniczo anonimową metodą. – dtb

Odpowiedz

267

Specyfikacja C# jawnie stwierdza (IIRC), że jeśli masz dwie anonimowe funkcje (metody anonimowe lub wyrażenia lambda), może on (ale nie musi) tworzyć równorzędnych delegatów z tego kodu. (Dwóch delegatów są równe, jeżeli mają równe cele i odnoszą się do tych samych metod.)

Aby mieć pewność, że trzeba pamiętać instancji delegata użyty:

EventHandler handler = (s, e) => MessageBox.Show("Woho"); 

button.Click += handler; 
... 
button.Click -= handler; 

(nie mogę znajdź odpowiedni fragment specyfikacji, ale zdziwiłbym się, gdyby kompilator C# agresywnie próbował stworzyć równych delegatów. Z pewnością nie byłoby rozsądnie polegać na nim.)

Jeśli nie chcesz robić to, musisz wyodrębnić metodę:

public void ShowWoho(object sender, EventArgs e) 
{ 
    MessageBox.Show("Woho"); 
} 

... 

button.Click += ShowWoho; 
... 
button.Click -= ShowWoho; 

Jeśli chcesz utworzyć procedurę obsługi zdarzeń, która usuwa się za pomocą wyrażenia lambda, jest nieco trudniejsza - musisz odwołać się do delegata w samym wyrażeniu lambda, a nie możesz tego zrobić za pomocą prostego polecenia "zadeklaruj lokalny zmienna i przypisanie jej za pomocą wyrażenia lambda ", ponieważ wtedy zmienna nie jest definitywnie przypisana. Zazwyczaj to obejść poprzez przypisanie wartości null do pierwszej zmiennej:

EventHandler handler = null; 
handler = (sender, args) => 
{ 
    button.Click -= handler; // Unsubscribe 
    // Add your one-time-only code here 
} 
button.Click += handler; 

Niestety to nie jest nawet łatwo ująć to w sposób, ponieważ zdarzenia nie są równo reprezentowane. Najbliższy można przyjść byłoby coś takiego:

button.Click += Delegates.AutoUnsubscribe<EventHandler>((sender, args) => 
{ 
    // One-time code here 
}, handler => button.Click -= handler); 

nawet to byłoby trudne do wdrożenia w ciągu Delegates.AutoUnsubscribe bo trzeba by utworzyć nowy EventHandler (co byłoby po prostu ogólny typ argument). Do zrobienia, ale niechlujny.

+1

Dokładnie, jeśli zajrzysz do swojego skompilowanego zestawu za pomocą Reflektora, zauważysz, że kompilator mimo wszystko utworzył dla ciebie wskaźnik, kiedy używasz lambda, po prostu nie widzisz go w Visual Studio – Raffaeu

+1

@Raffaeu: Wywołanie go jest nieco mylące - nie jest wskaźnikiem w normalnym znaczeniu słowa C# . –

+2

Tak, przepraszam, "kompilatory i tak utworzą zmienną obsługi" czy to lepiej? :) – Raffaeu

Powiązane problemy