Casting of generics?

P

psyCK0

Hi all!

I have a problem of casting generics to their base type. In the code
below I first define a BaseList class that can hold items of any type
that inherits from BaseItem. I then define a DerivedList that can hold
items of the type DerivedItem, which inherits from BaseList.
So far so good... But if I somehow get an object that I know is a
subclass of BaseList (and therefor holds subclasses of BaseItem) and
try to cast it to BaseList<BaseItem> i get an InvalidCastException
(also below).
Because both the list class and the item class(es) it contains can be
cast to their base classes I think that the whole should also be
castable? Or am I wrong? Is this an syntactic error or a thought fault?
=)

Regards,
Richard

Code (can also be found at http://pastebin.com/866977 )

class BaseItem {
}

class DerivedItem : BaseItem {
}

class BaseList<T> where T : BaseItem {
}

class DerivedList : BaseList<DerivedItem> {
}

class Program {
static void Main(string[] args) {
// Suppose i get this value (dl) from outside as an object.
// I only know that it is a subclass of BaseList and it is
// parameterized with some subclass of BaseItem
DerivedList dl = new DerivedList();
object o = dl;

// This cast fails!
BaseList<BaseItem> dl2 = (BaseList<BaseItem>) o;
}
}

Exception:

System.InvalidCastException was unhandled
Message="Unable to cast object of type 'TestConsoleApp.DerivedList'
to type 'TestConsoleApp.BaseList`1[TestConsoleApp.BaseItem]'."
Source="TestConsoleApp"
StackTrace:
at TestConsoleApp.Program.Main(String[] args) in Program.cs:line
28
at System.AppDomain.nExecuteAssembly(Assembly assembly, String[]
args)
at System.AppDomain.ExecuteAssembly(String assemblyFile,
Evidence assemblySecurity, String[] args)
at
Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object
state)
at System.Threading.ExecutionContext.Run(ExecutionContext
executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
 
K

Kevin Spencer

Remember that Generics allow you to create strong data types, and treat them
as such. So,

DerivedList : BaseList<DerivedItem>

is a strongly-typed BaseList, of type DerivedItem.

However, you are attempting to cast it to:

BaseList<BaseItem>

which is a strongly-typed BaseList of type BaseItem.

Now, if you were to cast it as

BaseList<DerivedItem>

which is the type it inherits, the cast would not fail.
BaseList<DerivedItem> does not inherit BaseList<BaseItem>.

--
HTH,

Kevin Spencer
Microsoft MVP
Software Composer
http://unclechutney.blogspot.com

The shortest distance between 2 points is a curve.
 
B

Bruce Wood

Hi all!

I have a problem of casting generics to their base type. In the code
below I first define a BaseList class that can hold items of any type
that inherits from BaseItem. I then define a DerivedList that can hold
items of the type DerivedItem, which inherits from BaseList.
So far so good... But if I somehow get an object that I know is a
subclass of BaseList (and therefor holds subclasses of BaseItem) and
try to cast it to BaseList<BaseItem> i get an InvalidCastException
(also below).
Because both the list class and the item class(es) it contains can be
cast to their base classes I think that the whole should also be
castable? Or am I wrong? Is this an syntactic error or a thought fault?
=)

It's a "thought fault". Think about it for a moment: if you could cast
a BaseList<DerivedItem> to a reference variable for a
BaseList<BaseItem>, then you could add BaseItems to the list, which
clearly violates the constraint that the list is of DerivedItems. For
example:

BaseList<Fireman> fireList = new BaseList<Fireman>();
BaseList<Person> personList = (BaseList<Person>)fireList;
personList.Add(new ComputerProgrammer());

If the second line were allowed, then the third line could not be
checked at compile time, which would incur a run-time cost (type
checking) for all operations on generics, which is precisely what
generics seek to avoid.

Generics make strong guarantees that can be verified at compile time,
and so need no run-time type checking.
 

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