Как преобразовать общий список <T>в список на основе интерфейса <T> - PullRequest
7 голосов
/ 16 февраля 2010

Я уверен, что мне не хватает чего-то простого, однако я пытаюсь преобразовать строго типизированный список объектов, которые реализуют интерфейс, в список этого типа интерфейса.

Ниже приведен пример для демонстрации ошибки:

public void ExampleCode(){
    List<Cube> cubes = new List<Cube>();
    List<Shape> allShapes;
    allShapes = cubes;//Syntax Error
    allShapes = (List<Shape>)cubes;//Syntax Error  
}

public class Cube : Shape
{
    public int ID { get; set; }
    public int Sides { get; set; }
}

public interface Shape
{
  int ID { get; set; }
  int Sides { get; set; }
}

Ответы [ 7 ]

13 голосов
/ 16 февраля 2010

Вместо того, чтобы так разыгрывать, попробуйте:

allShapes = cubes.Cast<Shape>().ToList();

Для этого вам нужен .NET 3.5. Я считаю, что метод расширения Cast можно найти в System.Linq.

6 голосов
/ 16 февраля 2010

Вы не можете. Потому что List<T> и ILIst<T> поддерживают только параметры инвариантного типа. Это значение равно T, которое одновременно используется для входных и выходных параметров (например, возвращаемых значений). В противном случае вы можете нарушить безопасность типа.

Другие интерфейсы (например, IEntumerable<T>) допускают некоторое отклонение.

См. Блог Эрика Липперта " Fabulous Adventures In Coding " для обсуждения противоречий и ко-дисперсий. В частности, тег " Ковариация и Контравариантность ".

Редактировать, только что добавленный в блог "Часто задаваемые вопросы по C #": Часто задаваемые вопросы о ковариантности и контравариантности

4 голосов
/ 16 февраля 2010

То, на что вы ссылаетесь, называется универсальной ковариацией и не поддерживается c # 3. Однако оно поддерживается c # 4 (.NET 4 / VS 2010), и вы можете прочитать об этом здесь:

Дисперсия в универсальных интерфейсах

Сказав это, IList<T> не является ковариантным (потому что он принимает и выставляет T). IEnumerable<T>, с другой стороны, является ковариантным (потому что он не принимает T).

2 голосов
/ 16 февраля 2010

Вы не можете сделать это, так как, разыгрывая этот путь, вы можете потерять безопасность всех типов. Например, приведение List<Shape> к List<object> приведет к тому, что объекты любого типа могут быть добавлены в список, что будет совершенно непоследовательным.

0 голосов
/ 16 февраля 2010

Это работает, если вы определите все формы как IEnumerable

В C # 4.0 вы можете просто назначить allshapes = cubes

Для C # 3.5 вы можете использовать allShapes = cubes.Select (c => ((Shape) c));

Но в любом случае вам нужно использовать IEnumerable вместо List

0 голосов
/ 16 февраля 2010

Нельзя приводить между списками типов, даже если сами типы являются конвертируемыми. Вам нужно будет создать новый список и заполнить его либо путем итерации исходного списка, либо с помощью ConvertAll. См. http://www.dev102.com/2008/05/15/how-to-convert-listt1-to-listt2/ для примера кода.

0 голосов
/ 16 февраля 2010

Вы также можете сделать:

allShapes = cubes.ConvertAll(x => (Shape)x);

Или, если вы делаете это в .NET 2.0:

allShapes = cubes.ConvertAll<Shape>(delegate(Cube c){
    return (Shape)c;
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...