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)?
The ' |= ' symbol is the bitwise OR assignment operator.
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 ...
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.
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.
Using LINQ:
List<Parent> parentList = childList.Cast<Parent>().ToList();
Documentation for Cast<>()
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/
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 { }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With