Is it possible to create a delegate for *any* Action<T>?
我想弄明白为什么这行不通:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public void DefaultAction( object obj = null ){} public void Start() { SomeReferenceType obj; DefaultAction( obj ); //works int i; string s; DefaultAction( i ); //works DefaultAction( s ); //works } //however... public event Action OnNullAction = DefaultAction; //works public event Action<SomeReferenceType> OnObjectAction = DefaultAction; //works public event Action<int> OnIntAction = DefaultAction; //doesn't work!! |
尝试将
您发现委托反向需要引用类型。
我知道,这是相当高傲的。
首先,让我清楚地说明协方差和反方差是什么。假设您在类型之间有一个关系:"类型
1 | Animal <-- Giraffe |
如果用
1 | IEnumerable<Animal> <-- IEnumerable<Giraffe> |
因为C 4.0,当我将此功能添加到语言中时,您可以在任何需要动物序列的地方使用长颈鹿序列。
如果替换方向与箭头方向相反,则在
1 | Action<Animal> --> Action<Giraffe> |
如果你需要一个要求你给它一个
那么
那
既然我们知道了泛型类型的协方差和反方差是什么,那么C中的规则是什么?规则是:
类型声明必须用
in 和out 注释。例如,delegate R Func 。注意,(A a) in 是进入函数的东西,out 是从函数中出来的东西,我们故意将它们命名为in 和out 。编译器必须能够证明注释是安全的。有关详细信息,请参阅规范或我的日志。
只有泛型委托和接口才支持方差,而不是泛型结构、枚举或类。
不同的类型必须都是引用类型。
现在我们来回答你的问题。为什么它们都必须是引用类型?你推断出答案:拳击教学在哪里?
1 2 3 | Action<object> oa = (object x)=>whatever; Action<int> ia = oa; // Suppose this works. ia(123); |
拳击教学在哪里?不是在分配给
1 2 | Action<object> oa = (object x)=>{whatever}; Action<int> ia = (int x)=>{ oa(x); }; |
但如果这就是你想说的,那就说吧。人们希望引用转换将保持引用标识,因此C禁止必须对值进行装箱或取消装箱的协变或逆变转换。
如果您对此有更多问题,请在我以前的博客(blogs.msdn.com/ericlippet)中搜索
只是让它通用
1 | public void DefaultAction<T>(T param) { } |