2010-01-12 39 views
46

Tôi đã tự hỏi liệu điều này có thực sự hoạt động không?Thêm và xóa Trình xử lý sự kiện ẩn danh

private void RegisterKeyChanged(T item) 
{ 
    item.OnKeyChanged += (o, k) => ChangeItemKey((T)o, k); 
} 

private void UnRegisterKeyChanged(T item) 
{ 
    item.OnKeyChanged -= (o, k) => ChangeItemKey((T)o, k); 
} 

Trình biên dịch biết các trình xử lý sự kiện giống nhau như thế nào? Điều này thậm chí còn được đề nghị?

+0

Có thể trùng lặp của [Hủy đăng ký phương thức ẩn danh trong C#] (https://stackoverflow.com/questions/183367/unsubscribe-anonymous-method-in-c-sharp) –

Trả lời

55

Có một trang MSDN rằng cuộc đàm phán về vấn đề này:

How to Subscribe to and Unsubscribe from Events

Lưu ý đặc biệt:

Nếu bạn sẽ không phải bỏ đăng ký tới [sic] một sự kiện sau đó, bạn có thể sử dụng toán tử gán thêm (+ =) để đính kèm một phương thức ẩn danh vào sự kiện .

Và cũng:

Điều quan trọng cần lưu ý rằng bạn không thể dễ dàng bỏ đăng ký từ một sự kiện nếu bạn sử dụng một chức năng ẩn danh để đăng ký nó. Để hủy đăng ký trong trường hợp này, nó là cần thiết để quay lại mã nơi bạn đăng ký sự kiện, lưu trữ phương thức ẩn danh trong ủy quyền biến và sau đó thêm đại biểu vào sự kiện. Nói chung, chúng tôi khuyên bạn nên sử dụng rằng bạn không sử dụng các chức năng vô danh để đăng ký sự kiện nếu bạn sẽ phải hủy đăng ký sự kiện tại một số điểm sau trong mã của bạn.

+0

Vì vậy, nó có nghĩa là, về cơ bản những gì trong OP không hoạt động như nghĩa vụ phải? Nó có nghĩa là đại biểu vô danh, nếu không được lưu trữ tại điểm đăng ký, gần như không thể hủy đăng ký? –

+0

Rõ ràng là có. –

1

Nếu bạn kiểm tra với tài liệu dành cho Đại biểu. Tính chất, bạn sẽ thấy chúng không được so sánh theo tham chiếu.

3

Tôi không tin điều này sẽ hiệu quả. Nếu bạn thực sự cần hủy đăng ký khỏi một sự kiện, bạn phải chỉ định trình xử lý sự kiện rõ ràng mà sau này bạn có thể hủy đăng ký thay vì một đại biểu ẩn danh.

2

Điều đó sẽ không hoạt động Tôi sợ, vì hai biểu thức lambda (và các đại biểu) mà bạn khai báo thực sự là các đối tượng khác nhau và trả về các tham chiếu khác nhau. Do đó, việc loại bỏ trình xử lý (-=) sẽ luôn thất bại.

Giải pháp chung cho vấn đề này (nơi bạn cần loại bỏ trình xử lý) chỉ đơn giản là tái cấu trúc biểu thức lamba thành một phương thức thích hợp. Một cách khác là duy trì một biến lớp cho đại biểu xử lý sự kiện, và thêm và loại bỏ điều này, mặc dù cá nhân tôi không phải là một fan của nó. (Đó là rắc rối hơn là chỉ tạo một phương pháp bình thường, nếu có.)

+0

Lưu ý, có một câu hỏi và câu trả lời tương tự ở , nơi Reed Copsey đề xuất giải pháp tương tự như tôi làm . – Noldorin

5

Nếu bạn cần hủy đăng ký một trình xử lý sự kiện, bạn sẽ cần phải có một tham chiếu xác định cho một đại biểu cụ thể. Nhìn vào Delegate.Equality bạn sẽ thấy rằng các đại biểu không chỉ được so sánh bằng cách sử dụng bình đẳng tham chiếu, tuy nhiên điều này không quan trọng cho các đại biểu vô danh.

Đối với một đại biểu ẩn danh, trình biên dịch (về cơ bản) chỉ tạo một đại biểu "không ẩn danh" mới cho mỗi đại biểu ẩn danh, ngay cả khi các đại biểu là như nhau. Bởi vì điều này, khuôn khổ sẽ không tìm thấy các đại biểu để bỏ đăng ký khi bạn sử dụng ví dụ mã bạn đã cho.

8

Đối với bất cứ ai quan tâm, bạn có thể thêm và loại bỏ một event handler vô danh như

public class Musician 
{ 
    public void TuneGuitar() 
    { 
     Metronome metronome = new Metronome(); 

     EventHandler<EventArgs> handler = null; 
     handler = (sender, args) => 
     { 
      // Tune guitar 
      // ... 

      // Unsubscribe from tick event when guitar sound is perfect 
      metronome.Tick -= handler; 
     }; 

     // Attach event handler 
     metronome.Tick += handler; 
    } 
} 

public class Metronome 
{ 
    event EventHandler<EventArgs> Tick; 
} 

CẬP NHẬT này: Trong C# 7.0 chúng tôi có hỗ trợ cho local functions nên phương pháp TuneGuitar bây giờ có thể được viết như sau:

public void TuneGuitar() 
{ 
    Metronome metronome = new Metronome(); 

    void handler = (object sender, EventArgs args) => 
    { 
     // Tune guitar 
     // ... 

     // Unsubscribe from tick event when guitar sound is perfect 
     metronome.Tick -= handler; 
    }; 

    // Attach event handler 
    metronome.Tick += handler; 
} 
Các vấn đề liên quan