2012-06-24 27 views
92

Khi sử dụng myDelegate -= eventHandler ReSharper (phiên bản 6) Các vấn đề:"Phép trừ đại biểu có kết quả không thể đoán trước" trong ReSharper/C#?

Đại biểu trừ có kết quả không thể đoán trước

Các hợp lý đằng sau này là explained by JetBrains here. Lời giải thích có ý nghĩa và, sau khi đọc nó, tôi nghi ngờ tất cả việc sử dụng của tôi là - đối với các đại biểu.

Làm thế nào sau đó,

  • tôi có thể viết một sự kiện không tự động mà không làm ReSharper gắt gỏng?
  • hoặc, có cách nào tốt hơn và/hoặc "chính xác" để triển khai điều này không?
  • hoặc, tôi có thể bỏ qua ReSharper không? đang

đây được đơn giản hóa:

public delegate void MyHandler (object sender); 

MyHandler _myEvent; 

public event MyHandler MyEvent 
{ 
    add 
    { 
     _myEvent += value; 
     DoSomethingElse(); 
    } 
    remove 
    { 
     _myEvent -= value; // <-- ReSharper warning here 
    } 
} 
+0

Mono đưa ra cảnh báo tương tự. Đây là mô tả của R # về vấn đề https://confluence.jetbrains.com/display/ReSharper/Delegate+subtraction+has+unpredictable+semantics (chỉ áp dụng cho các danh sách đại biểu) – thoredge

Trả lời

107

Đừng sợ! Phần đầu tiên của cảnh báo của ReSharper chỉ áp dụng cho việc xóa danh sách các đại biểu. Trong mã của bạn, bạn luôn xóa một đại biểu. Phần thứ hai nói về việc sắp xếp các đại biểu sau khi một đại biểu trùng lặp đã được gỡ bỏ. Một sự kiện không đảm bảo thứ tự thực thi cho người đăng ký của nó, vì vậy nó cũng không thực sự ảnh hưởng đến bạn.

Vì các cơ chế trên có thể dẫn đến kết quả không thể đoán trước, ReSharper đưa ra cảnh báo bất cứ khi nào gặp nhà điều hành phép trừ đại biểu.

ReSharper đang đưa ra cảnh báo này vì phép trừ đại biểu đa phương tiện có thể có gotchas, nó hoàn toàn không lên án tính năng ngôn ngữ đó. May mắn là những người mắc bệnh này đang ở trong các trường hợp rìa và bạn không thể gặp họ nếu bạn chỉ đang thiết kế các sự kiện đơn giản. Không có cách nào tốt hơn để triển khai các trình xử lý add/remove của riêng bạn, bạn chỉ cần chú ý.

Tôi khuyên bạn nên hạ cấp mức cảnh báo của ReSharper cho thư đó thành "Gợi ý" để bạn không bị coi thường về cảnh báo, thường hữu ích.

+0

Tôi cảm thấy hơi khó chịu hơn một chút đã :) –

+51

Tôi nghĩ rằng đó là xấu của R # để gọi kết quả "không thể đoán trước". Chúng được xác định rõ ràng. "Không phải những gì người dùng có thể dự đoán" không phải là bất kỳ cách nào giống như "không thể đoán trước". (Nó cũng không chính xác để nói rằng khuôn khổ .NET định nghĩa quá tải - nó được nướng vào trình biên dịch C#. 'Delegate' không * không * quá tải' + 'và' -'.) –

+6

@Jon: Tôi đồng ý. Tôi đoán tất cả mọi người đã quen với thanh cao Microsoft đặt cho chính nó. Mức độ đánh bóng cao như vậy, với rất nhiều thứ trong thế giới .NET khiến bạn "rơi vào hố thành công", gặp phải một tính năng ngôn ngữ chỉ là một bước đi nhanh bên cạnh hố, nơi có một cơ hội bạn có thể bỏ lỡ nó được xem xét bởi một số để được jarring và đảm bảo một dấu hiệu nói rằng "PIT OF THÀNH CÔNG LÀ R WNG --- ---'. –

-13

đặt thành = null thay vì sử dụng - =

+3

phương thức 'remove' của một sự kiện sẽ không loại bỏ tất cả các trình xử lý, mà đúng hơn là trình xử lý được yêu cầu xóa. – Servy

+0

nếu anh ta chỉ thêm một cái thì anh ta chỉ xóa một hiệu ứng mà anh ta đã xóa tất cả. Tôi không nói sử dụng nó trong mọi trường hợp chỉ dành cho thông báo chia sẻ lại cụ thể này. –

+3

Nhưng bạn * không * biết rằng đại biểu luôn loại bỏ mục duy nhất trên danh sách yêu cầu. Điều này làm cho thông báo chia sẻ lại biến mất bằng cách chuyển mã làm việc chính xác thành mã bị hỏng không chính xác, trong một số trường hợp, tình cờ hoạt động, nhưng điều đó sẽ phá vỡ theo cách khác thường và khó chẩn đoán trong nhiều trường hợp. – Servy

9

Bạn không được trực tiếp sử dụng đại biểu để tổng hoặc trừ. Thay vào đó, trường của bạn

MyHandler _myEvent; 

Thay vào đó, phải được tuyên bố là sự kiện. Điều này sẽ giải quyết được vấn đề mà không gây rủi ro cho giải pháp của bạn và vẫn có lợi ích của việc sử dụng sự kiện.

event MyHandler _myEvent; 

Sử dụng tổng đại biểu hoặc trừ là nguy hiểm vì bạn có thể mất các sự kiện khi chỉ đơn giản là gán các đại biểu (theo tuyên bố, các nhà phát triển sẽ không trực tiếp suy ra đây là một đại biểu Multicast như khi nó được khai báo là một sự kiện) . Chỉ cần minh họa, nếu thuộc tính được đề cập trong câu hỏi này không được gắn cờ như một sự kiện, đoạn mã dưới đây sẽ phân biệt hai lần gán đầu tiên là LOST, bởi vì ai đó chỉ được gán cho người được ủy nhiệm (cũng hợp lệ!).

myObject.MyEvent += Method1; 
myObject.MyEvent += Method2; 
myObject.MyEvent = Method3; 

Khi chỉ định Method3, tôi đã mất hoàn toàn hai đăng ký ban đầu. Việc sử dụng sự kiện sẽ tránh được sự cố này và đồng thời xóa cảnh báo ReSharper.

+0

Tôi chưa bao giờ nghĩ đến việc làm theo cách này, nhưng nó có ý nghĩa để bảo vệ việc sử dụng sự kiện của đại biểu miễn là bạn giữ sự kiện cơ bản đó ở chế độ riêng tư. Tuy nhiên, điều này không hoạt động tốt khi đồng bộ hóa chuỗi cụ thể hơn phải xảy ra trong trình xử lý thêm/xóa như nhiều đăng ký sự kiện hoặc đăng ký phụ cần được theo dõi. Tuy nhiên, trong mọi trường hợp, nó loại bỏ các cảnh báo. – Jeremy

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