Convert List DerivedClass to List BaseClass
The way to make this work is to iterate over the list and cast the elements. This can be done using ConvertAll:
List<A> listOfA = new List<C>().ConvertAll(x => (A)x);
You could also use Linq:
List<A> listOfA = new List<C>().Cast<A>().ToList();
Casting List of Derived class to List of base class
The reason you cannot do this is because a list is writable. Suppose it were legal, and see what goes wrong:
List<Cat> cats = new List<Cat>();
List<Animal> animals = cats; // Trouble brewing...
animals.Add(new Dog()); // hey, we just added a dog to a list of cats...
cats[0].Speak(); // Woof!
Well dog my cats, that is badness.
The feature you want is called "generic covariance" and it is supported in C# 4 for interfaces that are known to be safe. IEnumerable<T>
does not have any way to write to the sequence, so it is safe.
class Animal
{
public virtual void Play(IEnumerable<Animal> animals) { }
}
class Cat : Animal
{
public override void Play(IEnumerable<Animal> animals) { }
}
class Program
{
static void Main()
{
Cat cat = new Cat();
cat.Play(new List<Cat>());
}
}
That will work in C# 4 because List<Cat>
is convertible to IEnumerable<Cat>
, which is convertible to IEnumerable<Animal>
. There is no way that Play can use IEnumerable<Animal>
to add a dog to something that is actually a list of cats.
Convert List of Base Class to a List of Derived Class - possible?
Cast<T>
method applies cast operation to all elements of the input sequence. It works only if you can do the following to each element of the sequence without causing an exception:
ParentClass p = ...
ChildClass c = (ChildClass)p;
This will not work unless p
is assigned an instance of ChildClass
or one of its subclasses. It appears that in your case the data returned from the server API contains objects of ParentClass
or one of its subclasses other than ChildClass
.
You can fix this problem by constructing ChildClass
instances, assuming that you have enough information from the server:
List<ChildClass> childList = parentList
.Select(parent => new ChildClass(parent.Name, ... /* the remaining fields */))
.ToList();
Cannot convert from List DerivedClass to List BaseClass
It is because List<T>
is in-variant
, not co-variant
, so you should change to IEnumerable<T>
which supports co-variant
, it should work:
IEnumerable<BaseClass> bcl = new List<DerivedClass>();
public void doSomething(IEnumerable<BaseClass> bc)
{
// do something with bc
}
Information about co-variant in generic
Most efficient way to cast List SubClass to List BaseClass
The syntax for this sort of assignment uses a wildcard:
List<SubClass> subs = ...;
List<? extends BaseClass> bases = subs;
It's important to realize that a List<SubClass>
is not interchangeable with a List<BaseClass>
. Code that retains a reference to the List<SubClass>
will expect every item in the list to be a SubClass
. If another part of code referred to the list as a List<BaseClass>
, the compiler will not complain when a BaseClass
or AnotherSubClass
is inserted. But this will cause a ClassCastException
for the first piece of code, which assumes that everything in the list is a SubClass
.
Generic collections do not behave the same as arrays in Java. Arrays are covariant; that is, it is allowed to do this:
SubClass[] subs = ...;
BaseClass[] bases = subs;
This is allowed, because the array "knows" the type of its elements. If someone attempts to store something that isn't an instance of SubClass
in the array (via the bases
reference), a runtime exception will be thrown.
Generic collections do not "know" their component type; this information is "erased" at compile time. Therefore, they can't raise a runtime exception when an invalid store occurs. Instead, a ClassCastException
will be raised at some far distant, hard-to-associate point in code when a value is read from the collection. If you heed compiler warnings about type safety, you will avoid these type errors at runtime.
Converting a List of Base type to a List of Inherited Type
If you have linq available you can do
var ListOfA = ListOfB.Cast<A>().ToList();
.OfType () Extract Derived types from a Base Type List
This is asking the framework to figure out a little bit too much:
List<Melee> melee = chars.Where(c => c is Melee).ToList(); // doesnt work
Even though you're using Where
to filter out items that are only of type Melee
, the list you're filtering is of type Character
. So no matter how you filter the list of Character
, the result is an IEnumerable<Character>
, or List<Character>
after calling ToList()
.
You can't assign a List<Character>
to a variable declared as List<Melee>
.
You could do
List<Melee> melee = chars.Where(c => c is Melee).Cast<Melee>().ToList();
but the previous line where you use OfType
is simpler and clearer. OfType
is doing the same thing - selecting elements of the given type and casting them as that type.
Copying a List BaseClass to List DerivedClass
List<DerivedClass> result =
listBaseClass.ConvertAll(instance => (DerivedClass)instance);
Actually ConvertAll is good when you need to create new objects based on the original, when you just need to cast you can use the following
List<DerivedClass> result =
listBaseClass.Cast<DerivedClass>().ToList();
If not all of the items in your list can be cast to DerivedClass then use OfType instead
List<DerivedClass> result =
listBaseClass.OfType<DerivedClass>().ToList();
Downcasting a list of objects in C#
Using LINQ:
var baseList = new List<BaseClass>();
var derivedList = baseList.Cast<DerivedClass>();
Note: Having to downcast usually is a 'smell' and indicates that the inheritance hierarchy is wrong, or wrongly implemented. The idea of having a base class is that you can treat all subclasses as superclass without having to downcast to individual subclass types.
Instead of Cast
you might want to use OfType
to 'fish out' certain derived classes from a collection of superclasses. But again, there should be no need to do that.
Ask yourself, why you need to have a subclass - maybe you need to move some functionality to base class?
Related Topics
Determine the Number of Lines Within a Text File
How to Assign by "Reference" to a Class Field in C#
Cannot Use Ref or Out Parameter in Lambda Expressions
How to Set a Property Value with Reflection
Calling a Method Every X Minutes
Changing the User Agent of the Webbrowser Control
Most Efficient Way to Remove Special Characters from String
C# Listview, How to Add Items to Columns 2, 3 and 4 etc
How to Read a Large (1 Gb) Txt File in .Net
How to Bind an Enum to a Combobox Control in Wpf
No Output to Console from a Wpf Application
How to Close a Streamwriter Without Closing Its Basestream
How to Animate a Line on a Canvas in C#
Using Excel Oledb to Get Sheet Names in Sheet Order
Asynchronous Locking Based on a Key