В 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));