我有以下界面
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# Interfaces and Generic Lists 然后我最终得到了以下方法
public List<IMyInterface> getItems(int id)
{
return new List<MyClass>().Cast<IMyInterface>().ToList();
}
这将编译,但对我来说,处理它似乎是一种非常奇怪的方式;将具体类转换为接口。在线程C# Interfaces and Generic Lists Aequitarum Custos对接受的答案的评论表明不应该这样做。
我错过了什么或是这样做的吗?
答案 0 :(得分:3)
因为尽管Base
是Parent
的子类型,但并不意味着List<Base>
是List<Parent>
的子类型。 IList<T>
在其通用参数中是不变的,List<T>
也是如此(c#不支持类方差,只支持接口方差)。
在此处阅读有关协方差,逆变和不变性的更多信息:http://blogs.msdn.com/b/csharpfaq/archive/2010/02/16/covariance-and-contravariance-faq.aspx
如果List<T>
是协变的,并且您被允许这样做:
List<Parent> list = new List<Base>();
如果你这样做会怎么样?
list.Add(new OtherBase());
这在编译时肯定是合法的,但会导致运行时错误。
答案 1 :(得分:2)
这是因为List<T>
中的T
参数不是covariant。但它在IEnumerable<out T>
:
out T
要枚举的对象类型。
此类型参数是协变的。也就是说,您可以使用指定的类型或更多派生的类型。
如果您考虑更改getItems
的签名:
public IEnumerable<IMyInterface> getItems(int id)
{
return new List<MyClass>() as IEnumerable<IMyInterface>;
}
您可以找到有关协方差和逆转 here的更多信息。
答案 2 :(得分:0)
考虑这个例子:
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();