Как привести Список <ClassB>в Список <ClassA>, когда ClassB наследует от ClassA? - PullRequest
10 голосов
/ 31 октября 2011

Я десериализовал строку json в List<ClassB> и теперь хочу преобразовать ее в List<ClassA>, прежде чем вернуть ее из BindModel метод. Мне нужно приведение, потому что методы ожидают получить List<ClassA>.

Почему я получаю ошибку во время приведения? В конце концов, ClassB наследуется от ClassA. Что мне делать?

P.S. этот вопрос расширен с на этот пост . В строке new DataContractJsonSerializer(typeof(List<ClassB>)); вместо List<ClassB> тип будет создан во время выполнения.

    public override object BindModel(...)
    {
          var serializer = new DataContractJsonSerializer(typeof(List<ClassB>));
          MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes("[{\"id\":\"1\",\"name\":\"name\"}]"));
          var list = serializer.ReadObject(ms);

          return (List<ClassA>)list;
    }

    [KnownType(typeof(ClassA))]
    [DataContract]
    public class ClassA
    {
        public ClassA();
    }

    [KnownType(typeof(ClassB))]       
    [DataContract]
    public class ClassB : ClassA
    {
        [DataMember(Name = "id")]
        public int Id { get; set; }
        [DataMember(Name = "name")]
        public string CategoryName { get; set; }
    }

Ответы [ 5 ]

10 голосов
/ 31 октября 2011

Вы можете использовать

 Cast<T>()

Например:

 List<A> listOfA = new List<B>().Cast<A>();

Это фактически уступает Linq и реализовано на IEnumerable вместо IEnumerable<T> но все же полезно. неэффективен , поскольку, как я уже сказал, он пытается его разыграть.

Запоминание списка не допускает ковариацию , что является помехойЖелательно использовать IEnumerable<T> в качестве интерфейса, а не List.

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

 IEnumerable<B> listOfB = new List<B>();
 IEnumerable<A> listOfA = listOfB; // no casting required
6 голосов
/ 31 октября 2011

Вы можете использовать Метод приведения .

return list.Cast<ClassB>();

Посмотрите на этот вопрос о Co и Contra Variance

2 голосов
/ 31 октября 2011

Я бы разыграл списки так:

var listB = GetListOfB();  // returns List<B>
var listA = listB.Select(q => (A)q).ToList();

Будет ли это работать для вас?

1 голос
/ 31 октября 2011

Чтобы создать List<BaseClass> из List<DerivedClass>, броска будет недостаточно, как отмечали другие ответы. Вам нужно построить новый список.

Я не особо доволен кодом, предложенным другими ответами, поэтому я предлагаю свое собственное решение. Я бы сделал это так:

var baseClassList = new List<BaseClass>(derivedClassList.Cast<BaseClass>());

Некоторые могут предпочесть это:

var baseClassList = derivedClassList.Cast<BaseClass>().ToList();

Я предпочитаю первый, потому что он позволяет легко изменить тип с List<T> на любой другой набор с конструктором, который принимает IEnumerable<T>.

1 голос
/ 31 октября 2011

Нельзя преобразовать список подтип в список супертип .Предположим, у меня есть список черепах, и я смог привести его к списку животных.Тогда я мог бы добавить льва в список черепах, но лев не того типа.

Однако с помощью перечислимых функций вы можете сделать это.Предыдущие постеры совершенно правы, говоря, что вы можете привести Список Подтип к IEnumerable SuperType .Фактически, в C # 4 и IEnumerable SubType является IEnumerable со значением SuperType .Это связано с тем, что универсальный параметр указан как выходной параметр.

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