我有一个函数,其签名为
Update(IEnumberable<INotifyPropertyChanging> things)
和一个类
doohickey : INotifyPropertyChanging, INotifyPropertyChanging{}
当我尝试做
List<doohickey> doohickeys = new List<doohickey>();
Update(doohickeys);
抛出异常,说明:
cannot convert from 'System.Collections.Generic.List<doohickey>' to 'System.Collections.Generic.IEnumerable<System.ComponentModel.INotifyPropertyChanging>'
什么给出了? Doohickey继承了INotifyPropertyChanging接口(interface),List继承了IEnumerable接口(interface)!为什么简单地传递对象并期望它被强制转换却不会呢?
我添加了对 INotifyPropertyChanging 的引用,以表明 doohickey 实际上是一个 linq-to-sql 类;万一上下文很重要。
最佳答案
这不起作用,因为 List<doohickey>
之间没有隐式转换。和IEnumerable<NotifyPropertyChanging>
。您需要调用:
Update(doohickeys.Cast<INotifyPropertyChanging>());
这背后的原因是类型安全。在 C#4 中,语言中添加了协/逆变,这通常有助于使这些类型的转换有效。但有一些限制,因为涉及的类型需要声明为协变/逆变,并且它仅适用于接口(interface)和委托(delegate)。
无法隐式转换的原因List<T>
至List<TBase>
也就是说,它将使此代码有效:
List<T> values = new List<T>();
// add some values...
List<TBase> bases = values;
bases.Add(new TBase()); // Woops. We broke type safety by adding a TBase to a list of T's
现在,如果您尝试在 values
时执行此操作类型为IEnumerable<T>
,这在 C#4 中是有效的。这是因为您只能从 IEnumerable<T>
中获取值 ,所以我们不需要担心添加较少的类型。因此IEnumerable<T>
是协变的,并且声明为:
IEnumerable<out T>
哪里out
意思是“协变”。 (关键字实际上是记住变体类型中值的走向的最佳方式。
协方差/逆变是一个相当大的主题,but this article does a good job of explaining the most important parts 。如果您想了解更多信息,Eric Lippert 有一个 11-part blog post series关于该功能。 Eric 是语言设计师之一。
关于c# - 无效参数 - 继承的接口(interface)有效,但隐式转换则不然。是什么赋予了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4493686/