В C# возможно ли преобразовать List<Child> в List<Parent>?

Я хочу сделать что-то вроде этого:

List<Child> childList = new List<Child>();
...
List<Parent> parentList = childList;

Однако, поскольку parentList является предком Списка ребенка, а не прямым предком, я не могу этого сделать. Есть ли обходной путь (кроме добавления каждого элемента отдельно)?

6 ответов

Решение

Непосредственное приведение не разрешено, потому что нет способа сделать его безопасным. Если у вас есть список жирафов и вы добавили его в список животных, вы можете добавить тигра в список жирафов! Компилятор не остановит вас, потому что, конечно, тигр может войти в список животных. Единственное место, где компилятор может остановить вас, - небезопасное преобразование.

В C# 4 мы будем поддерживать ковариацию и контравариантность интерфейсов SAFE и типов делегатов, которые параметризованы ссылочными типами. Смотрите здесь для деталей:

http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

Используя LINQ:

List<Parent> parentList = childList.Cast<Parent>().ToList();

Документация дляCast<>()

Еще в 2009 году Эрик дразнил нас, что в C# 4 все изменится. Итак, где мы находимся сегодня?

Классы, использованные в моем ответе, можно найти внизу. Чтобы сделать это проще, мы будем использовать Mammal класс как "родитель", и Cat а также Dog классы как "дети". Кошки и собаки - это млекопитающие, но кошка не собака, а собака не кошка.

Это все еще не законно, и не может быть:

List<Cat> cats = new List<Cat>();

List<Mammal> mammals = cats;

Почему бы и нет? Кошки - это млекопитающие, так почему мы не можем назначить список кошек List<Mammal>?

Потому что, если бы нам было разрешено хранить ссылку на List<Cat> в List<Mammal> переменная, то мы сможем скомпилировать следующий код, чтобы добавить собаку в список кошек:

mammals.Add(new Dog());

Мы не должны этого допустить! Помните, mammals это просто ссылка на cats, Dog не сходить с Cat и не имеет права быть в списке Cat объекты.

Начиная с.NET Framework 4, несколько универсальных интерфейсов имеют параметры ковариантного типа, объявленные с помощью out Ключевое слово модификатора введено в C# 4. Среди этих интерфейсов IEnumerable<T> что, конечно, реализуется List<T>,

Это означает, что теперь мы можем разыграть List<Cat> для IEnumerable<Mammal>:

IEnumerable<Mammal> mammalsEnumerable = cats;

Мы не можем добавить новый Dog в mammalsEnumerable так как IEnumerable<out T> это интерфейс "только для чтения", то есть он не имеет Add() метод, но теперь мы можем использовать cats где бы IEnumerable<Mammal> можно употреблять Например, мы можем объединить mammalsEnumerable с List<Dog> вернуть новую последовательность:

void Main()
{
    List<Cat> cats = new List<Cat> { new Cat() };
    IEnumerable<Mammal> mammalsEnumerable =
        AddDogs(cats); // AddDogs() takes an IEnumerable<Mammal>
    Console.WriteLine(mammalsEnumerable.Count()); // Output: 3. One cat, two dogs.
}

public IEnumerable<Mammal> AddDogs(IEnumerable<Mammal> parentSequence)
{
    List<Dog> dogs = new List<Dog> { new Dog(), new Dog() };
    return parentSequence.Concat(dogs);
}

Определения классов:

public abstract class Mammal { }

public class Cat: Mammal { }

public class Dog : Mammal { }

Вы можете сделать это, используя подход Linq метода apply extension, то есть:

List<Parent> parentList = childList.Cast<Parent>().ToList();

Не делайте этого:

      List<Parent> parentList = childList.Cast<Parent>().ToList();

Дочерний класс не следует использовать в качестве родительского, если вы хотите передать список в качестве параметра метода, который получаетlist<parent>, вам нужно изменить параметр метода, используя IEnumerable, подробнее IEnumerable.

      public void methodA(IEnumerable<parent> param){}

Теперь вы можете использовать этот метод следующим образом:

      var oListChild = new List<child>();
methodA(oListChild);

Да, вы можете сделать это как

var result = List.And(x => x.Parent.All(b => b.ParentId == value));
Другие вопросы по тегам