Casting List<> of derived class to List<> of base class?

M

matty.hall

I have two classes: a base class (BaseClass) and a class deriving from
it (DerivedClass). I have a List<DerivedClass> that for various
reasons needs to be of that type, and not a List<BaseClass>. However, I
need to cast that list to a List<BaseClass> and it is not working. The
code is below. I get the following exception:

"Unable to cast object of type 'System.Collections.Generic.List`1' to
type 'System.Collections.Generic.List`1'."

Replacing the line "baseClasses = (List<BaseClass>) temp;" with
"baseClasses = (List<BaseClass>) derivedClasses" causes the compiler to
show an error:

"Cannot convert type
'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>' to
'System.Collections.Generic.List<ConsoleApplication1.BaseClass>'"

Is there anyway to accomplish this? Code follows...


using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<DerivedClass> derivedClasses;
List<BaseClass> baseClasses;
object temp;

derivedClasses = new List<DerivedClass>();
temp = derivedClasses;
baseClasses = (List<BaseClass>) temp;
}
}

public abstract class BaseClass {}
public abstract class DerivedClass : BaseClass { }
}
 
M

matty.hall

One more thing...

I do know about List<>.ConvertAll. However, I can't use this because
the type of the Derived class is not known at compile time (i.e. there
will be DerivedClassOne, DerivedClassTwo, etc and we don't know which
one it is because this conversion is actually happening in the base
class, which isn't a fact show in the code above, which I omitted to
keep the pasted code short).

The problem is that doing doing ConvertAll() with a Converter declared
as Converter<BaseClass, BaseClass> throws a compile time error "The
type arguments for method
'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>.ConvertAll<TOutput>(System.Converter<ConsoleApplication1.DerivedClass,TOutput>)'
cannot be inferred from the usage. Try specifying the type arguments
explicitly."

Alternatively, at runtime I know the type of the derived class from
GetType(). However, I don't know how (or if it is even possible) to
declare a generic type using runtime type information (i.e. something
like Converter<this.GetType(), BaseClass>).

Any thoughts?
 
J

Jon Skeet [C# MVP]

I have two classes: a base class (BaseClass) and a class deriving from
it (DerivedClass). I have a List<DerivedClass> that for various
reasons needs to be of that type, and not a List<BaseClass>. However, I
need to cast that list to a List<BaseClass> and it is not working. The
code is below. I get the following exception:

"Unable to cast object of type 'System.Collections.Generic.List`1' to
type 'System.Collections.Generic.List`1'."

Replacing the line "baseClasses = (List<BaseClass>) temp;" with
"baseClasses = (List<BaseClass>) derivedClasses" causes the compiler to
show an error:

"Cannot convert type
'System.Collections.Generic.List<ConsoleApplication1.DerivedClass>' to
'System.Collections.Generic.List<ConsoleApplication1.BaseClass>'"

Is there anyway to accomplish this? Code follows...

No. List<DerivedClass> isn't derived from List<BaseClass>. If it were,
you'd be able to do:

List<String> x = new List<String>();
List<Object> y = x;

y.Add (new Object()); // Bang! x is only meant to contain strings...
 
M

matty.hall

FWIW, this is what actually works:

using System;
using System.Collections.Generic;

namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
List<DerivedClass> derivedClasses;
BaseClass[] baseClasses;

derivedClasses = new List<DerivedClass>();
baseClasses = derivedClasses.ToArray();
}
}

public abstract class BaseClass { }
public class DerivedClass : BaseClass { }
}
 
N

Nicholas Paldino [.NET/C# MVP]

Yes, that works, but the problem that Jon points out still exists. If
you tried to take baseClasses and populate a List<DerivedClass> with it, it
could fail at runtime. This is the risk you run if you have to go the other
way.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top