2010-04-06 27 views
27

Vì vậy, tôi đã đọc xung quanh rằng thay vì gọi một sự kiện trực tiếp vớiTrình xử lý sự kiện không phải là chủ đề an toàn?

if (SomeEvent != null) 
    SomeEvent(this, null); 

tôi nên làm

SomeEventHandler temp = SomeEvent; 
if (temp != null) 
    temp(this, null); 

Tại sao điều này như vậy? Phiên bản thứ hai trở thành chủ đề an toàn như thế nào? Thực hành tốt nhất là gì?

+0

Đọc qua các câu trả lời đầy đủ, dự kiến ​​ở đây tôi hiểu được rằng xử lý sự kiện trong C# được kết hợp chặt chẽ, dễ bị lỗi và không được hiểu rõ. – micahhoover

Trả lời

13

Sự kiện thực sự là cú pháp đường trong danh sách đại biểu. Khi bạn gọi sự kiện, điều này thực sự lặp qua danh sách đó và gọi mỗi đại biểu với các tham số bạn đã vượt qua.

Sự cố với chủ đề là họ có thể thêm hoặc xóa các mục khỏi bộ sưu tập này bằng cách đăng ký/hủy đăng ký. Nếu họ làm điều này trong khi bạn đang lặp lại những bộ sưu tập này sẽ gây ra vấn đề (Tôi nghĩ rằng một ngoại lệ được ném)

Mục đích là để sao chép danh sách trước khi lặp lại nó, vì vậy bạn được bảo vệ chống lại những thay đổi vào danh sách.

Lưu ý: Tuy nhiên, hiện tại người gọi của bạn có thể được gọi ngay cả sau khi bạn hủy đăng ký, vì vậy bạn nên đảm bảo bạn xử lý điều này trong mã người nghe của mình.

+2

Thực ra, nó sẽ không gây ra sự cố khi bạn lặp lại bộ sưu tập. Các đại biểu chơi ở đây là bất biến. Vấn đề duy nhất là phân chia thứ hai trước khi kiểm tra xem có ai đã đăng ký và thực sự gọi trình xử lý sự kiện hay không. Khi bạn đã bắt đầu thực hiện chúng, không có thay đổi nền nào sẽ ảnh hưởng đến lời gọi hiện tại. –

5

Thực tiễn tốt nhất là biểu mẫu thứ hai. Lý do là một luồng khác có thể null hoặc thay đổi SomeEvent giữa thử nghiệm 'if' và lời gọi.

+0

Tại sao điều đó không thể xảy ra trong câu lệnh thứ hai? – Daniel

+2

Đọc là của 'SomeEvent' là nguyên tử, tức là nó xảy ra tất cả các cách hoặc không có gì. Vì vậy, 'temp' không thể được sửa đổi bên ngoài chủ đề đó do là một địa phương. – user7116

+0

Ooops 's/Như vậy/Đồng thời /' – user7116

2

Here là cách viết tốt về các sự kiện .NET và điều kiện chủng tộc có chủ đề. Nó bao gồm một số kịch bản phổ biến và có một số tài liệu tham khảo tốt trong đó.

Hy vọng điều này sẽ hữu ích.

+0

Cảm ơn bạn đã liên kết – Daniel

29

IMO, các câu trả lời khác bỏ sót một chi tiết chính - đại biểu đó (và do đó sự kiện) là bất biến. Ý nghĩa của việc này là việc đăng ký hoặc hủy đăng ký trình xử lý sự kiện không chỉ cần thêm/xóa vào danh sách - thay vào đó, nó thay thế danh sách bằng một danh sách mới có mục bổ sung (hoặc ít hơn) trên đó.

Kể từ tài liệu tham khảo là nguyên tử, điều này có nghĩa rằng tại thời điểm bạn làm:

var handler = SomeEvent; 

bây giờ bạn có một cứng nhắc dụ rằng không thể thay đổi, ngay cả khi ở pico giây tiếp theo khác unsubscribes ren (gây ra thực tế trường sự kiện để trở thành null).

Vì vậy, bạn thử nghiệm cho null và gọi nó, và tất cả là tốt. Lưu ý tất nhiên là có vẫn còn kịch bản khó hiểu của sự kiện là đã tăng trên một đối tượng nghĩ rằng nó đã hủy đăng ký một picosecond trước đây!

+0

Điều đó giải quyết một mối quan ngại, nhưng bản thân việc thay thế đã được thực hiện một cách an toàn sao cho đảm bảo rằng tất cả các hoạt động được yêu cầu đều xảy ra? Tức là, nếu hai chủ đề cố gắng đăng ký các đại biểu riêng biệt cùng một lúc, nó có được đảm bảo rằng cả hai sẽ được đăng ký cuối cùng hoặc có thể cho một trong các đăng ký đó không thành công không? – binki

+1

@binki yes; nó sử dụng một vòng trao đổi liên khóa (trình biên dịch hiện đại), hoặc một vùng đồng bộ ('khóa') (các trình biên dịch cũ hơn) –

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