2009-09-01 26 views
187

Bản sao có thể xảy ra:
Unsubscribe anonymous method in C#
How do I Unregister ‘anonymous’ event handlerLàm thế nào để xóa trình xử lý sự kiện lambda

Gần đây tôi phát hiện ra rằng tôi có thể sử dụng để tạo ra lambdas xử lý sự kiện đơn giản. Ví dụ: tôi có thể đăng ký một sự kiện nhấp chuột như sau:

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

Nhưng bạn sẽ hủy đăng ký nó như thế nào?

+0

Xem tại đây: http://stackoverflow.com/questions/183367 –

+0

Bạn đã thử toán tử - = chưa? – Maciek

+1

@Svish: Một lambda về bản chất là một phương pháp ẩn danh. – dtb

Trả lời

267

Đặc tả C# nêu rõ (IIRC) rằng nếu bạn có hai hàm ẩn danh (các phương thức nặc danh hoặc biểu thức lambda) có thể hoặc không thể tạo các đại biểu bằng nhau từ mã đó. (Hai đại biểu đều bình đẳng nếu họ có mục tiêu bình đẳng và tham khảo các phương pháp tương tự.)

Để chắc chắn, bạn sẽ cần phải nhớ thể hiện ủy nhiệm bạn sử dụng:

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

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

(Tôi không thể tìm bit liên quan của spec, nhưng tôi sẽ khá ngạc nhiên khi thấy trình biên dịch C# tích cực cố gắng tạo ra các đại biểu bình đẳng. Nó chắc chắn sẽ là không khôn ngoan để dựa vào nó.)

Nếu bạn không muốn làm bạn sẽ cần phải trích xuất một phương thức:

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

... 

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

Nếu bạn muốn tạo trình xử lý sự kiện tự xóa bằng cách sử dụng biểu thức lambda, điều này hơi phức tạp - bạn cần tham khảo đại biểu trong biểu thức lambda và bạn không thể làm điều đó bằng cách đơn giản "khai báo cục bộ biến và gán cho nó bằng cách sử dụng một biểu thức lambda "bởi vì sau đó biến không chắc chắn được gán. Bạn thường làm được việc này bằng cách gán một giá trị null vào biến đầu tiên:

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

Đáng tiếc là nó thậm chí không dễ dàng để đóng gói này thành một phương pháp, bởi vì sự kiện không được sạch sẽ đại diện. Gần nhất bạn có thể đến sẽ là một cái gì đó như:

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

Thậm chí đó sẽ là khó khăn để thực hiện trong vòng Delegates.AutoUnsubscribe bởi vì bạn sẽ phải tạo ra một mới EventHandler (mà sẽ chỉ là một đối số kiểu generic). Doable, nhưng lộn xộn.

+1

Chính xác, nếu bạn nhìn vào bên trong bộ sưu tập được biên dịch bằng Reflector, bạn sẽ nhận thấy rằng trình biên dịch đã tạo ra một con trỏ cho bạn anyway khi bạn sử dụng lambda, nó chỉ là bạn không nhìn thấy nó trong Visual Studio – Raffaeu

+1

@Raffaeu: Gọi nó là một con trỏ là một chút gây hiểu lầm - nó không phải là một con trỏ trong C# bình thường của từ . –

+2

Có xin lỗi, "các trình biên dịch sẽ tạo biến biến xử lý" là nó tốt hơn? :) – Raffaeu

Các vấn đề liên quan