2008-08-19 27 views
19

Giả sử chúng ta có phương pháp sau đây:Có thể sử dụng lambdas làm trình xử lý sự kiện gây rò rỉ bộ nhớ không?

private MyObject foo = new MyObject(); 

// and later in the class 

public void PotentialMemoryLeaker(){ 
    int firedCount = 0; 
    foo.AnEvent += (o,e) => { firedCount++;Console.Write(firedCount);}; 
    foo.MethodThatFiresAnEvent(); 
} 

Nếu lớp với phương pháp này được khởi tạo và phương pháp PotentialMemoryLeaker được gọi là nhiều lần, làm chúng tôi bị rò rỉ bộ nhớ?

Có cách nào để mở trình xử lý sự kiện lambda đó sau khi chúng tôi gọi xong MethodThatFiresAnEvent không?

+0

Như đã nêu trong các câu trả lời dưới đây, không có cách nào để mở móc ra nó mà không cần bảo tồn một tham chiếu. Tuy nhiên, bạn có thể tự ẩn: http://stackoverflow.com/questions/1747235/weak-event-handler-model-for-use-with-lambdas/1747236#1747236 – Benjol

Trả lời

16

Có, lưu vào biến và mở khóa.

DelegateType evt = (o, e) => { firedCount++; Console.Write(firedCount); }; 
foo.AnEvent += evt; 
foo.MethodThatFiresAnEvent(); 
foo.AnEvent -= evt; 

Và vâng, nếu bạn không, bạn sẽ rò rỉ bộ nhớ, như bạn sẽ treo lên một đối tượng delegate mới mỗi lần. Bạn cũng sẽ nhận thấy điều này bởi vì mỗi lần bạn gọi phương thức này, nó sẽ đổ đến bàn điều khiển một số dòng ngày càng tăng (không chỉ là một số ngày càng tăng, nhưng đối với một cuộc gọi đến MethodThatFiresAnEvent nó sẽ đổ bất kỳ số lượng mục nào, một lần cho mỗi hooked lên phương pháp vô danh).

0

Có cùng cách xử lý sự kiện thông thường có thể gây rò rỉ. Bởi vì lambda thực sự được thay đổi thành:

someobject.SomeEvent +=() => ...; 
someobject.SomeEvent += delegate() { 
    ... 
}; 

// unhook 
Action del =() => ...; 
someobject.SomeEvent += del; 
someobject.SomeEvent -= del; 

Vì vậy, về cơ bản nó chỉ là ngắn tay cho những gì chúng tôi đã sử dụng trong 2.0 tất cả những năm này.

4

Bạn sẽ không chỉ bị rò rỉ bộ nhớ, bạn cũng sẽ nhận được lambda của bạn được gọi là nhiều lần. Mỗi cuộc gọi của 'PotentialMemoryLeaker' sẽ thêm một bản sao lambda khác vào danh sách sự kiện và mọi bản sao sẽ được gọi khi 'AnEvent' được kích hoạt.

1

Ví dụ của bạn chỉ biên dịch sang lớp bên trong riêng được trình biên dịch có tên (với trường firedCount và phương thức có tên trình biên dịch). Mỗi cuộc gọi tới PotentialMemoryLeaker sẽ tạo ra một cá thể mới của lớp đóng, trong đó foo giữ một tham chiếu bằng cách ủy nhiệm cho phương thức duy nhất.

Nếu bạn không tham khảo toàn bộ đối tượng sở hữu PotentialMemoryLeaker, thì tất cả sẽ là rác được thu thập. Nếu không, bạn có thể thiết lập foo null hoặc sự kiện danh sách handler trống foo của bằng cách viết này:

foreach (var handler in AnEvent.GetInvocationList()) AnEvent -= handler; 

Tất nhiên, bạn sẽ cần truy cập vào các thành viên riêng MyObject lớp của.

3

Vâng, bạn có thể mở rộng những gì đã được thực hiện here để làm cho các đại biểu an toàn hơn để sử dụng (không có rò rỉ bộ nhớ)

+1

liên kết đã chết – thumbmunkeys

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