Có một mẫu chuẩn cho các sự kiện trong .NET - chúng sử dụng loại delegate
lấy một đối tượng đơn giản gọi là người gửi và sau đó là "trọng tải" thực tế trong tham số thứ hai, bắt nguồn từ EventArgs
.Tôi sẽ mất gì bằng cách bỏ mẫu EventHandler chuẩn trong .NET?
Lý do cho thông số thứ hai có nguồn gốc từ EventArgs
có vẻ khá rõ ràng (xem .NET Framework Standard Library Annotated Reference). Nó được thiết kế để đảm bảo khả năng tương thích nhị phân giữa các sự kiện chìm và các nguồn khi phần mềm phát triển. Đối với mọi sự kiện, ngay cả khi nó chỉ có một đối số, chúng tôi lấy được một lớp đối số sự kiện tùy chỉnh có một thuộc tính duy nhất chứa đối số đó, để chúng tôi giữ khả năng thêm nhiều thuộc tính hơn vào tải trọng trong các phiên bản sau mà không vi phạm mã máy khách hiện tại . Rất quan trọng trong một hệ sinh thái của các thành phần phát triển độc lập.
Nhưng tôi thấy rằng điều này cũng tương tự với 0 đối số. Điều này có nghĩa là nếu tôi có một sự kiện không có đối số trong phiên bản đầu tiên của tôi và tôi viết:
public event EventHandler Click;
... thì tôi đang làm sai. Nếu tôi thay đổi loại đại biểu trong tương lai thành một lớp mới làm trọng tải của nó:
public class ClickEventArgs : EventArgs { ...
... Tôi sẽ phá vỡ tính tương thích nhị phân với khách hàng của tôi. Các khách hàng kết thúc lên đến một quá tải cụ thể của một phương pháp nội bộ add_Click
mà mất EventHandler
, và nếu tôi thay đổi loại đại biểu sau đó họ không thể tìm thấy tình trạng quá tải, do đó, có một MissingMethodException
.
Được rồi, vậy nếu tôi sử dụng phiên bản chung tiện dụng thì sao?
public EventHandler<EventArgs> Click;
Không, vẫn sai, vì EventHandler<ClickEventArgs>
không phải là EventHandler<EventArgs>
.
Vì vậy, để có được lợi ích của EventArgs
, bạn có để lấy được từ nó, thay vì sử dụng trực tiếp như vậy. Nếu bạn không, bạn có thể cũng không được sử dụng nó (có vẻ như với tôi).
Sau đó, có đối số đầu tiên, sender
. Dường như với tôi giống như một công thức cho khớp nối không độc. Một sự kiện bắn về cơ bản là một cuộc gọi chức năng. Nếu chức năng, nói chung, có khả năng đào trở lại thông qua ngăn xếp và tìm ra ai là người gọi, và điều chỉnh hành vi của nó cho phù hợp? Chúng ta có nên ủy thác giao diện đó trông như thế này không?
public interface IFoo
{
void Bar(object caller, int actualArg1, ...);
}
Sau khi tất cả, implementor của Bar
có thể muốn biết caller
là ai, vì vậy họ có thể truy vấn để biết thêm thông tin! Tôi hy vọng bạn đang puking bây giờ. Tại sao nó lại khác biệt cho các sự kiện?
Vì vậy, ngay cả khi tôi sẵn sàng chịu nỗi đau khi tạo một lớp độc lập cho mỗi sự kiện tôi tuyên bố, chỉ để làm cho nó đáng giá trong khi sử dụng EventArgs
, tôi chắc chắn muốn bỏ đối số người gửi đối tượng .
trực quan tính năng tự động hoàn Studio dường như không quan tâm những gì đại biểu bạn sử dụng cho một sự kiện - bạn có thể gõ +=
[nhấn Space, Return] và nó viết một phương pháp xử lý đối với các bạn rằng các trận đấu bất cứ đại biểu nó sẽ xảy ra là .
Vì vậy, tôi sẽ mất giá trị nào bằng cách lệch khỏi mẫu chuẩn?
Như một câu hỏi tiền thưởng, C#/CLR 4.0 có làm bất cứ điều gì để thay đổi điều này, có lẽ thông qua contravariance trong các đại biểu? Tôi đã cố gắng điều tra điều này nhưng nhấn another problem. Ban đầu tôi bao gồm khía cạnh này của câu hỏi trong câu hỏi khác, nhưng nó gây ra sự nhầm lẫn ở đó. Và nó có vẻ hơi nhiều để chia này thành tổng cộng ba câu hỏi ...
Cập nhật:
Hóa ra tôi đã đúng khi tự hỏi về những tác động của contravariance trên toàn bộ vấn đề này!
Là noted elsewhere, quy tắc trình biên dịch mới để lại một lỗ hổng trong hệ thống kiểu thổi lên khi chạy. Lỗ đã được cắm một cách hiệu quả bằng cách xác định EventHandler<T>
khác với Action<T>
.
Vì vậy, đối với các sự kiện, để tránh lỗ loại đó, bạn không nên sử dụng Action<T>
. Điều đó không có nghĩa là bạn phải sử dụng EventHandler<TEventArgs>
; nó chỉ có nghĩa rằng nếu bạn sử dụng một loại đại biểu chung, không chọn một trong đó được kích hoạt cho contravariance.
Hãy quan tâm để nghe lý do từ người bỏ phiếu. –
Tôi đã không bỏ phiếu theo một trong hai cách, nhưng tôi nghi ngờ downvote là bởi vì bạn đã có ít nhất hai câu hỏi trong một ở đây. Tôi không muốn thực sự cố gắng giải quyết toàn bộ bản thân mình, nhưng tôi rất vui khi nhìn vào khía cạnh khác biệt (như tôi đang viết về nó ngay bây giờ). Nếu bạn có thể tách các bit dẫn đến một lỗi thời gian thực hiện vào một câu hỏi riêng biệt với một trường hợp ngắn nhưng đầy đủ để tái tạo nó, tôi sẽ được quan tâm ... –
Sẽ làm [PADDING] –