Как правильно вернуть тип списка интерфейсов? - PullRequest
7 голосов
/ 25 ноября 2010

С помощью следующего кода я получаю «неспособность неявным образом привести» ошибку компиляции в «книги возврата»; линия.

Я думал, что, поскольку я возвращаю список объектов книги, которые реализуют 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 ]

9 голосов
/ 25 ноября 2010

Проблема в том, что 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, лучше просто использовать первый предложенный мной метод.

2 голосов
/ 25 ноября 2010

Это не безопасное преобразование.Представьте себе, если кто-то поместит журнал в ваш список книг.

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>, как описано здесь , без создания каких-либо новых объектов.cdhowie также дает хороший обходной путь для более низких версий.Просто бросьте .ToList() и верните IEnumerable.

Я понимаю, что ваш конкретный случай безопасен.Но компилятор не может это проверить.

1 голос
/ 25 ноября 2010

Вам придется использовать обходной путь, если вы не используете .NET 4.

Подумайте, должен ли кто-нибудь сделать это:

public class Magazine : IPublication { }

// Somewhere...

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

Если среда выполнения позволила преобразование из List<Book> до List<IPublication>, тогда вам будет разрешено добавлять журналы в список книг!Это нарушает систему типов, потому что если бы что-то все еще имело ссылку на List<Book>, оно по праву не ожидало бы, что Magazine будет в нем, оно будет обрабатывать Magazine, как если бы это была книга, а затем время выполненияпоследуют сбои (или что еще хуже - повреждение данных или небезопасные вещи).

0 голосов
/ 25 ноября 2010

Я думаю, вы работаете над старыми версиями вместо c # 4.0, где у нас есть ковариация и контравариантность . Таким образом, вы можете конвертировать элемент списка только по элементу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...