为什么方法不能声明返回类型`List <imyinterface>`并返回实现它的具体类</imyinterface>

时间:2014-01-23 11:39:40

标签: c# generics return-type

我有以下界面

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对接受的答案的评论表明不应该这样做。

我错过了什么或是这样做的吗?

3 个答案:

答案 0 :(得分:3)

因为尽管BaseParent的子类型,但并不意味着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();