Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C#, is it possible to cast a List<Child> to List<Parent>?

I want to do something like this:

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

However, because parentList is a List of Child's ancestor, rather than a direct ancestor, I am unable to do this. Is there a workaround (other than adding each element individually)?

like image 977
Matthew Avatar asked Nov 22 '09 04:11

Matthew


People also ask

What does |= mean in C?

The ' |= ' symbol is the bitwise OR assignment operator.

What is '~' in C programming?

In mathematics, the tilde often represents approximation, especially when used in duplicate, and is sometimes called the "equivalency sign." In regular expressions, the tilde is used as an operator in pattern matching, and in C programming, it is used as a bitwise operator representing a unary negation (i.e., "bitwise ...

What are operators in C?

C operators are one of the features in C which has symbols that can be used to perform mathematical, relational, bitwise, conditional, or logical manipulations. The C programming language has a lot of built-in operators to perform various tasks as per the need of the program.

What is the use of in C?

In C/C++, the # sign marks preprocessor directives. If you're not familiar with the preprocessor, it works as part of the compilation process, handling includes, macros, and more.


3 Answers

Using LINQ:

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

Documentation for Cast<>()

like image 131
recursive Avatar answered Oct 08 '22 15:10

recursive


Casting directly is not allowed because there's no way to make it typesafe. If you have a list of giraffes, and you cast it to a list of animals, you could then put a tiger into a list of giraffes! The compiler wouldn't stop you, because of course a tiger may go into a list of animals. The only place the compiler can stop you is at the unsafe conversion.

In C# 4 we'll be supporting covariance and contravariance of SAFE interfaces and delegate types that are parameterized with reference types. See here for details:

https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/covariance-contravariance/

like image 20
Eric Lippert Avatar answered Oct 08 '22 15:10

Eric Lippert


Back in 2009 Eric teased us that things would change in C# 4. So where do we stand today?

The classes used in my answer can be found at the bottom. To make this easier to follow, we will use a Mammal class as "parent", and Cat and Dog classes as "children". Cats and dogs are both mammals, but a cat is not a dog and a dog is not a cat.

This still isn't legal, and can't be:

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

List<Mammal> mammals = cats;

Why not? Cats are mammals, so why can't we assign a list of cats to a List<Mammal>?

Because, if we were allowed to store a reference to a List<Cat> in a List<Mammal> variable we would then be able to compile the following code to add a dog to a list of cats:

mammals.Add(new Dog());

We mustn't allow that! Remember, mammals is just a reference to cats. Dog does not descend from Cat and has no business being in a list of Cat objects.

Starting with .NET Framework 4, several generic interfaces have covariant type parameters declared with the out Generic Modifier keyword introduced in C# 4. Amongst these interfaces is IEnumerable<T> which of course is implemented by List<T>.

That means we can now cast a List<Cat> to an IEnumerable<Mammal>:

IEnumerable<Mammal> mammalsEnumerable = cats;

We can't add a new Dog to mammalsEnumerable because IEnumerable<out T> is a "read-only" interface i.e. it has no Add() method, but we can now use cats wherever a IEnumerable<Mammal> can be consumed. For example, we can concatenate mammalsEnumerable with a List<Dog> to return a new sequence:

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

Class definitions:

public abstract class Mammal { }

public class Cat: Mammal { }

public class Dog : Mammal { }
like image 38
Stephen Kennedy Avatar answered Oct 08 '22 15:10

Stephen Kennedy