我有以下接口
public interface IMyInterface
{
// Some method and property signatures
}
我有以下类实现上述接口
的类public class MyClass : IMyInterface
{
// Some methods and properties as declared by IMyInterface
}
然后,我在某些随机类中有此方法,我想返回实现IMyInterface
的对象列表。在此特定的实现中,这些对象是MyClass
的实例。
public List<IMyInterface> getItems(int id)
{
return new List<MyClass>();
}
这将导致编译错误(在Visual Studio中也可以实时可见)
不能隐式转换类型 'System.Collections.generic.LIST&lt; myclass&gt;' 到 'system.collections.generic.list&lt; imyinterface&gt;'
我搜索了互联网,终于找到了这个线程C#接口和通用列表然后,我最终得到了以下方法
public List<IMyInterface> getItems(int id)
{
return new List<MyClass>().Cast<IMyInterface>().ToList();
}
这会编译,但是对我来说,这似乎是一种处理它的奇怪方法。将混凝土类施放到界面。在线程c#接口和通用列表中,aeeeequitarum custos对接受答案的评论表明不必这样做。
我错过了什么还是这样做的方法?
,因为即使Base
是Parent
的子类型,也不意味着List<Base>
是List<Parent>
的子类型。IList<T>
在其通用参数中是不变的,List<T>
也是如此(C#不支持类方差,仅接口差异)。
在此处阅读有关协方差,违反和不变性的更多信息:http://blogs.msdn.com/b/csharpfaq/archive/2010/02/02/16/covariance-and-contravariance-and-contravariance-faq.aspx.aspx
如果List<T>
是协变量的,您可以这样做:
List<Parent> list = new List<Base>();
如果您这样做会发生什么?
list.Add(new OtherBase());
这在编译时肯定是合法的,但会导致运行时错误。
这是因为 List<T>
中的 T
参数不是 variant 。但它在IEnumerable<out T>
中:
out t
列举的对象类型。
此类型参数是协变量的。也就是说,您可以使用指定的类型或更派生的任何类型。
因此,如果您考虑更改getItems
的签名:
public IEnumerable<IMyInterface> getItems(int id)
{
return new List<MyClass>() as IEnumerable<IMyInterface>;
}
您可以找到有关协方差和 contravariance 的更多信息。
考虑此示例:
public interface IAnimal
{
}
public class Cat : IAnimal
{
}
public class Dog : IAnimal
{
}
您等效的方法:
public List<IAnimal> getAnimals()
{
return new List<Dog>();
}
// You just Dog'd a list of Cats
IEnumerable<Cat> cats = getAnimals();