Trong khi điều tra this question Tôi đã tò mò về cách tính hiệp phương sai/đối xứng mới trong C# 4.0 sẽ ảnh hưởng đến nó.Sự kiện và ủy quyền đối nghịch trong .NET 4.0 và C# 4.0
Trong bản Beta 1, C# dường như không đồng ý với CLR. Sao lưu trong C# 3.0, nếu bạn có:
public event EventHandler<ClickEventArgs> Click;
... và sau đó ở nơi khác bạn có:
button.Click += new EventHandler<EventArgs>(button_Click);
... trình biên dịch sẽ barf vì chúng là hai loại đại biểu không tương thích. Nhưng trong C# 4.0, nó biên dịch tốt, bởi vì trong CLR 4.0 tham số kiểu bây giờ được đánh dấu là in
, do đó, nó là contravariant, và do đó trình biên dịch giả định đại biểu multicast +=
sẽ hoạt động.
Dưới đây là thử nghiệm của tôi:
public class ClickEventArgs : EventArgs { }
public class Button
{
public event EventHandler<ClickEventArgs> Click;
public void MouseDown()
{
Click(this, new ClickEventArgs());
}
}
class Program
{
static void Main(string[] args)
{
Button button = new Button();
button.Click += new EventHandler<ClickEventArgs>(button_Click);
button.Click += new EventHandler<EventArgs>(button_Click);
button.MouseDown();
}
static void button_Click(object s, EventArgs e)
{
Console.WriteLine("Button was clicked");
}
}
Nhưng mặc dù nó biên dịch, nó không hoạt động trong thời gian chạy (ArgumentException
: Các đại biểu phải có cùng loại).
Sẽ ổn nếu bạn chỉ thêm một trong hai loại đại biểu. Nhưng sự kết hợp của hai loại khác nhau trong một multicast gây ra ngoại lệ khi thứ hai được thêm vào.
Tôi đoán đây là lỗi trong CLR trong bản beta 1 (hành vi của trình biên dịch có vẻ hy vọng đúng).
Cập nhật cho Release Candidate:
Đoạn mã trên không còn biên dịch. Nó phải được rằng các contravariance của TEventArgs
trong loại EventHandler<TEventArgs>
đại biểu đã được cuộn lại, do đó, bây giờ mà đại biểu có định nghĩa tương tự như trong .NET 3.5.
Đó là, các phiên bản beta Tôi nhìn phải có:
public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);
Bây giờ nó trở lại:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
Nhưng tham số Action<T>
đại biểu T
vẫn contravariant:
public delegate void Action<in T>(T obj);
Tương tự với Func<T>
's T
là biến thể.
Thỏa hiệp này có ý nghĩa rất nhiều, miễn là chúng tôi giả định rằng việc sử dụng chính các đại biểu đa phương tiện là trong ngữ cảnh của các sự kiện. Cá nhân tôi thấy rằng tôi không bao giờ sử dụng các đại biểu đa phương tiện ngoại trừ các sự kiện.
Vì vậy, tôi đoán các tiêu chuẩn mã hóa C# giờ đây có thể áp dụng quy tắc mới: không tạo thành đại biểu đa phương tiện từ nhiều loại đại biểu có liên quan thông qua hiệp phương sai/contravariance. Và nếu bạn không biết điều đó có nghĩa là gì, chỉ cần tránh sử dụng Action
để các sự kiện ở bên an toàn.
Tất nhiên, kết luận rằng có ý nghĩa đối với the original question that this one grew from ...
Thắc mắc thú vị của bạn muốn là câu hỏi? –
Tôi ngạc nhiên lỗ này thoát khỏi thông báo của đội C#, nên là một trong những điều đầu tiên họ sẽ thử nghiệm sau khi giới thiệu phương sai cho các đại biểu chung không phải là nó? C# 5 cũng trưng bày nó (phiên bản clr giống nhau). – nawfal