con*_*low 35 c# delegates .net-4.0 covariance
C#4.0协同和逆变支持的一些奇怪行为:
using System;
class Program {
static void Foo(object x) { }
static void Main() {
Action<string> action = _ => { };
// C# 3.5 supports static co- and contravariant method groups
// conversions to delegates types, so this is perfectly legal:
action += Foo;
// since C# 4.0 much better supports co- and contravariance
// for interfaces and delegates, this is should be legal too:
action += new Action<object>(Foo);
}
}
Run Code Online (Sandbox Code Playgroud)
这是结果 ArgumentException: Delegates must be of the same type.
奇怪,不是吗?为什么Delegate.Combine()(+=在对代理执行操作时调用)不支持运行时的协同和逆转?
而且,我发现BCL的System.EventHandler<TEventArgs>委托类型没有对它的泛型TEventArgs参数进行逆变注释!为什么?它完全合法,TEventArgs仅在输入位置使用.也许没有逆变注释,因为它很好地隐藏了错误Delegate.Combine()?;)
ps所有这些都会影响VS2010 RC及更高版本.
Eri*_*ert 38
长话短说:代表组合在方差方面都搞砸了.我们在周期的后期发现了这一点.我们正在与CLR团队合作,看看我们是否能够提出一些方法来使所有常见方案在不破坏向后兼容性的情况下工作,等等,但无论我们提出什么,都可能无法进入4.0版本.希望我们能在一些服务包中整理出来.我带来的不便表示歉意.
协方差和逆变指定了泛型类型之间的继承关系.当你有协方差和逆变时,类G<A>和G<B>可能在某种继承关系中取决于什么A和B是什么.调用泛型方法时,您可以从中受益.
但是,该Delegate.Combine方法不是通用的,文档清楚地说明何时抛出异常:
ArgumentException- a和b都不是null引用(Nothing在Visual Basic中),而a和b不是同一委托类型的实例.
现在,Action<object>和Action<string>是肯定不同的委托类型(即使通过继承关系的关联)的情况下,所以根据该文件,它会抛出异常.这种Delegate.Combine方法可以支持这种情况听起来是合理的,但这只是一个可能的提议(显然直到现在才需要这样做,因为你不能声明继承的委托,所以在co/contra-variance之前,没有委托有任何继承关系).