无效的参数 - 继承的接口,作为工作,隐式转换不会。是什么赋予了?

时间:2010-12-20 20:35:05

标签: c# linq interface

我有一个具有

签名的函数
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接口,List继承了IEnumerable接口!为什么简单地传递对象并期望它被抛弃呢?

我已经包含了对INotifyPropertyChanging的引用,以表示doohickey实际上是一个linq-to-sql类;如果上下文很重要。

1 个答案:

答案 0 :(得分:3)

这不起作用,因为List<doohickey>IEnumerable<NotifyPropertyChanging>之间没有隐式转换。你需要打电话:

Update(doohickeys.Cast<INotifyPropertyChanging>());

背后的原因是类型安全。在C#4中,语言中添加了共同/逆变,这通常有助于使这些类型的转换有效。但是存在一些限制,因为涉及的类型需要声明为co / contravariant,并且它仅适用于接口和委托。

您无法将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是语言设计师之一。