2011-03-04 25 views
5

Nếu tôi tạo ra một lớp .NET mà đặt mua một sự kiện với một chức năng vô danh như thế này:Tôi có cần xóa loại xử lý sự kiện này không?

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

sẽ xử lý sự kiện này là một gốc giữ lớp học của tôi từ được thu thập rác?

Nếu không, wohoo! Nhưng nếu có, bạn có thể chỉ cho tôi cú pháp xóa không? Chỉ cần sử dụng - = với cùng một mã có vẻ sai.

Trả lời

3

Bạn có thể sử dụng một phương pháp "thực" như Simon D. gợi ý, hoặc làm điều này:

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

Do đây là hơi xấu xí và đánh bại mục đích của việc sử dụng một lambda được succint, tôi muốn có thể đi với refactoring nó ra một phương pháp. Nhưng nó rất hữu ích để biết những gì khác hoạt động.

Cảnh báo: Nó đi mà không nói rằng bạn phải siêu siêu cẩn thận để không gây rối với các giá trị của handler ở tất cả giữa điểm mà bạn đăng ký vào trường và điểm nơi nó được thực sự gọi, nếu không thì phần hủy đăng ký sẽ không hoạt động chính xác.

+0

Tôi thích phong cách succint ở đây. Đối với nhu cầu của tôi, điều này sẽ hoạt động hoàn hảo. Cảm ơn bạn đã dành thời gian viết bài này! – jschroedl

3

Tôi nghĩ bạn cần phải hủy đăng ký, bởi vì nhà cung cấp sự kiện (ứng dụng) sống - hoặc ít nhất có thể sống - lâu hơn người tiêu dùng của bạn. Vì vậy, mỗi trường hợp đăng ký chết trong khi ứng dụng vẫn còn sống sẽ tạo ra rò rỉ bộ nhớ.

Bạn đang đăng ký một đại biểu ẩn danh cho sự kiện. Đây là lý do tại sao bạn không thể hủy đăng ký nó theo cùng một cách, bởi vì bạn không thể giải quyết nó nữa. Thực ra bạn đang tạo phương thức tại cùng thời điểm bạn đăng ký, và bạn không lưu bất kỳ con trỏ nào vào phương thức mới tạo.

Nếu bạn hơi thay đổi thực hiện của bạn phải sử dụng một phương pháp "thực", bạn có thể dễ dàng bỏ đăng ký từ sự kiện này giống như cách bạn đăng ký với nó:

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

Cảm ơn bạn đã xác nhận sự nghi ngờ. -John – jschroedl

1

Đây thực sự là một sự rò rỉ có thể ngăn chặn thu gom rác thải. Có nhiều cách xung quanh nó - với WeakReference là một trong những cái tốt hơn.

This link có cuộc trò chuyện tốt và câu trả lời hay cho bạn.

+0

Cảm ơn con trỏ. Những người đó trở nên xinh xắn như thế này !! – jschroedl

2

Bạn chắc chắn phải dọn sạch tham chiếu. Nếu có bất kỳ nghi ngờ nào bạn có thể dễ dàng kiểm tra với sự kiện tĩnh của riêng bạn như vậy.

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

Sau đó, bằng cách thiết lập một breakpoint trong hàm remove bạn có thể thấy rằng các bạn tham khảo được không dọn dẹp.

class Program 
{ 
    static void Main(string[] args) 
    { 
     foo f = new foo(); 
     MemoryLeak.ActivateLeak += o => f.bar(); 
     f.tryCleanup(); 
    } 
} 

class foo 
{ 
    public void bar() 
    { } 

    public void tryCleanup() 
    { 
     MemoryLeak.ActivateLeak -= o => bar(); 
    } 
} 

Là giải pháp thay thế cho giải pháp của Simon, bạn có thể sử dụng lần đóng thứ hai để tạo ra một hành động "tách rời".

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(); 
Các vấn đề liên quan