在调查这个问题,我好奇的新的协方差/逆变功能如何在C#4.0会影响它。
在Beta 1中,C#似乎与CLR不同意。 早在C#3.0中,如果你有:
public event EventHandler<ClickEventArgs> Click;
...然后你在其他地方有:
button.Click += new EventHandler<EventArgs>(button_Click);
...编译器会BARF,因为他们是不兼容的委托类型。 但在C#4.0中,它编译罚款,因为在CLR 4.0类型参数现在被标记为in
,所以它是逆变的,所以编译器假定多播委托+=
会工作。
下面是我的测试:
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");
}
}
但是,尽管它编译,它在运行时不工作( ArgumentException
:代表必须是同一类型的)。
这没关系,如果你只添加两个委托类型的任何一个。 但两种不同类型的在多播的组合导致当第二个被添加的异常。
我想这是在Beta 1中(编译器的行为看起来希望右)CLR中的错误。
更新发布候选:
上面的代码不再编译。 它必须是的逆变TEventArgs
在EventHandler<TEventArgs>
委托类型已经被回滚,所以现在该委托具有相同的定义,在.NET 3.5。
也就是说,我看了一定有公测:
public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e);
现在又回到:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
但Action<T>
委托参数T
仍然逆变:
public delegate void Action<in T>(T obj);
这同样适用于Func<T>
的T
是协变。
这一妥协使得有很大的意义,只要我们假定组播代表的主要用途是在事件的上下文中。 我个人发现,我从来没有使用多路广播委托,除非事件。
所以我想C#编码标准,现在可以采用新的规则:不形成从通过协方差/逆变相关多次委托类型多路广播委托。 如果你不知道这意味着什么,只是避免使用Action
事件是在安全方面。
当然,这个结论对影响原来的问题,这从一个成长 ...