christok
christok

Reputation: 1107

Cast list of interface to list of objects

I have a method that returns List<ThisInterface>. I would expect that I would be able to cast the results of that method to List<ThisClass>, as long as ThisClass implements ThisInterface. However, I receive the following error trying to do so:

Unable to cast object of type System.Collections.Generic.List'1[IThisInterface] to type System.Collections.Generic.List’1[ThisClass].

Any thoughts? Do I need to write a constructor for this?

Upvotes: 1

Views: 727

Answers (3)

Adam G
Adam G

Reputation: 1333

No (by way of example)

IAnimal animal = new Giraffe(); // Giraffe is an IAnimal so OK.
Lion lion = (Lion)animal; // should this work? Lion is an IAnimal???

Update:

For some it must be stated that Giraffe and Lion both implement an interface called IAnimal and that Giraffe is not a subclass of Lion. Others managed to understand that IThisInterface is akin to IAnimal and ThisClass is akin to Lion with a rhetorical "should this work".

The answer is self evidently no. A Lion is a concretion of IAnimal, but it does not follow that having an instance of IAnimal means that you have a Lion. Such a cast will throw but is also obviously wrong and so neatly illustrates the problem. In the same way, ThisClass implementing IThisInterface means that ThisClass is a concretion of IThisInterface, but just because you find yourself in possession of a collection of IThisInterface's, does not mean that you can assume that such is a list of ThisClass's. It might be, but equally it might be any other object that implements IThisInterface.

Anyway, if you search for covariance and contravariance you will find a number of similar questions that will let you understand further.

Upvotes: -3

poke
poke

Reputation: 388313

If you have a List<IThisInterface>, then you cannot cast that list object to List<ThisClass>. Even if all the items inside of the list are ThisClass objects, the list is still a list of IThisInterface objects.

What you need to do is create a new List<ThisClass> list and then populate that with all the items of the original list but cast those to ThisClass first.

Fortunately, that is exactly what the LINQ method Enumerable.Cast<T> does:

List<IThisInterface> list = GetData();

// cast the list to a `ThisClass` list
List<ThisClass> newList = list.Cast<ThisClass>().ToList();

Upvotes: 3

Mark Adelsberger
Mark Adelsberger

Reputation: 45819

I'm afraid your expectation is incorrect. A List<IThisInterface> is allowed to contain elements of any type that implements IThisInterface. If you were allowed to cast this to List<ThisClass>, the cast would add a restriction - suddenly only a specific implementation of the interface would be allowed in the list, and for example when you get an item from the list you would be allowed to assume it is of type ThisClass - which it may or may not be since what you were given was a less restrictive list.

Upvotes: 1

Related Questions