Event and delegate contravariance in .NET 4.0 and C# 4.0
在研究这个问题时,我很好奇C 4.0中的新协方差/反方差特性将如何影响它。
在beta 1中,c似乎不同意clr。回到C 3.0,如果你有:
1 | public event EventHandler<ClickEventArgs> Click; |
…然后在其他地方你有:
1 |
…编译器会死机,因为它们是不兼容的委托类型。但是在C 4.0中,它编译得很好,因为在clr 4.0中,类型参数现在标记为
这是我的测试:
2但尽管它是编译的,但它在运行时不工作(
如果只添加这两种委托类型中的任何一种,也可以。但是多播中两种不同类型的组合会在添加第二种类型时导致异常。
我想这是测试版1的clr中的一个bug(编译器的行为看起来很有希望是正确的)。
发布候选的更新:
上述代码不再编译。必须是
也就是说,我看到的贝塔一定有:
1 | public delegate void EventHandler<in TEventArgs>(object sender, TEventArgs e); |
现在又回到:
4但
1 | public delegate void Action<in T>(T obj); |
同样适用于
只要我们假定多播委托的主要用途是在事件上下文中,这种折衷就非常有意义。我个人发现,除了作为事件之外,我从不使用多播代理。
所以我想C编码标准现在可以采用一个新的规则:不要从多个通过协方差/反方差相关的委托类型中形成多播委托。如果你不知道这意味着什么,那就避免使用
当然,这个结论对这个问题的起源有一定的启示。
非常有趣。您不需要使用事件来看到这种情况的发生,实际上,我发现使用简单的委托更简单。
以
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | using System; class Program { static void Main(string[] args) { Func<string> stringFactory = () =>"hello"; Func<object> objectFactory = () => new object(); Func<object> multi1 = stringFactory; multi1 += objectFactory; Func<object> multi2 = objectFactory; multi2 += stringFactory; } } |
这编译得很好,但是两个
这绝对是一个问题,尽管我不确定解决方案应该是什么。在执行时,委托代码可能需要根据所涉及的委托类型计算出最适合使用的类型。有点讨厌。有一个通用的
值得注意的一点是,协变转换是一个引用转换——在上面,
1 |
(此时,下一行将无一例外地执行)在执行时,BCL确实必须处理
它很讨厌,我真的希望它能以某种方式得到修复。我会提醒马兹和埃里克这个问题,这样我们可以得到更多的信息评论。
我只需要在我的申请中解决这个问题。我做了以下工作:
2我不知道常规的多播事件是否存在相关差异。就我而言,它是有效的…
顺便说一下:我从来都不喜欢C中的活动。我不明白为什么有语言特性,当它不提供任何优势时。
你是否从两者中都得到了争论例外?如果只由新的处理程序抛出异常,那么我认为它是向后兼容的。
顺便说一句,我想你的意见有点混乱。在C 3中:
不会跑的。那是C 4