如何正确返回接口列表类型?

时间:2010-11-25 04:44:37

标签: c# list interface

使用以下代码,我在“return books”上收到“无法隐式转换”编译错误。线。

我认为,因为我要返回一个实现IPublication的图书对象列表,这应该可以正常工作吗?

public interface IPublication {}

public class Book : IPublication {}

public List<IPublication> GetBooks()
{
    List<Book> books = new List<Book>();
    return books;
}

我注意到,如果我将一本书作为单个IPublication对象返回,则可以正常工作。引入List<>需要明确的演员。

作为我正在使用的解决方法:

return books.Cast<IPublication>().ToList();

4 个答案:

答案 0 :(得分:8)

问题是List<IPublication>可以容纳任何继承自IPublication的类。由于编译器不知道您不会尝试将Magazine放入GetBooks()的结果中,因此您必须编写如下函数:

public List<IPublication> GetBooks() 
{ 
    List<IPublication> books = new List<IPublication>(); 
    // put only books in here
    return books; 
} 

如果你的函数返回一个不需要通过索引访问的不可变列表(并且你在C#4上),你可以这样写:

public IEnumerable<IPublication> GetBooks()         
{         
    List<Book> books = new List<Book>();         
    return books;         
}

如果您可以返回IEnumerable<T>但是您正在使用C#3,那么您可以执行cdhowie建议的内容:

public IEnumerable<IPublication> GetBooks()         
{         
    List<Book> books = new List<Book>();         
    return books.Cast<IPublication>();         
}

如果您使用的是C#2,最好只使用我提出的第一种方法。

答案 1 :(得分:2)

这不是一个安全的转换。想象一下,如果有人将杂志放在你的书籍清单中。

public class Library
{
    public List<Book> books = new List<Book>();
    public List<IPublication> GetBooks()
    {
      return books;
    }
}

其他地方,

Magazine mag = ...;
List<IPublication> pubs = someLibrary.GetBooks()
pubs.Add(mag);

在.NET 4中,您可以返回IEnumerable<IPublication>,如here所述,而不创建任何新对象。 cdhowie还为较低版本提供了良好的解决方案。只需删除.ToList(),然后返回IEnumerable

我意识到你的具体案例是安全的。但编译器无法验证。

答案 2 :(得分:1)

除非您使用的是.NET 4,否则必须使用解决方法。

考虑是否有人这样做:

public class Magazine : IPublication { }

// Somewhere...

var foo = something.GetBooks();
foo.Add(new Magazine());

如果运行时允许从List<Book>转换为List<IPublication>,那么您将被允许将杂志添加到书籍列表中!这打破了类型系统,因为如果某些内容仍然引用了List<Book>,那么它肯定不会指望Magazine在其中,它会将Magazine视为好像一本书,然后运行时崩溃(或者更糟 - 数据损坏或不安全的事情)随之而来。

答案 3 :(得分:0)

我认为您正在使用旧版本而不是c#4.0,我们有covariance and contravariance。 所以你只能按元素转换list元素。