Share via


Object to Generic List<> cast

Question

Thursday, March 26, 2009 5:44 AM

I've a method with a property of type List<ChildClass>. I'm calling getting the value of this with reflection, and I get an object, when debug it shows that the object has correct data. When i try to cast the object to List<IMyInterface> (ChildClass implements IMyInterface> i get the following error:

Cannot cast 'objData' (which has an actual type of 'System.Collections.Generic.List<ChildClass>') to 'System.Collections.Generic.List<IMyInterface>'

what is that i'm doing wrong???

All replies (6)

Thursday, March 26, 2009 2:26 PM âś…Answered | 2 votes

Eyal-Shilony has a good description of the underlying problem. BTW, this is one thing that they're looking at fixing in .NET 4.0.
 
To fix this problem now, you can cast to (non-generic) IList and then use LINQ to cast each object:

IList objList = (IList)objData;  
int count = objList.Count; // The LINQ conversions will lose this information  
IEnumerable<IMyInterface> list = objList.Cast<IMyInterface>(); 

       -Steve


Thursday, March 26, 2009 7:19 AM

Hello,

Nothing is wrong, except the fact you're trying to cast a lemon tree to an ordinary tree of citrus fruits, having a collection of A and a collection of IA are two different things regardless of A implementing IA.

So in that case you can have a collection of IA, which will allow you to add objects of A.


.Net developer and software consultant.


Friday, March 27, 2009 12:53 AM

Here is the example:

        List<string> list = new List<string>();
        list.Add("Hi");
        list.Add("Bye");

        object obj = list;

        I can do simply casting here as it's the same type.
        list = (List<string>)o;

        And loop through list, and print values. It will print:
        Hi
        Bye

But if it's not the same type as in question (implement interface), we can do exactly suggested by Stephen.

Here also LINQ comes for help.

        IList iList = (IList)obj;
        IEnumerable<string> list2 = iList.Cast<string>();

        foreach (string str in list2)
        {
            Label1.Text += str + "</br>";
        }

        And loop through list, and print values. It will print:
        Hi
        Bye

Hope this helps.


Friday, March 27, 2009 1:28 AM

Stephen, do you know how they plan on fixing this in .Net 4.0?
I find this quite annoying when you have a method from another library with this signature:

public void DoSomething(List<object>); 

If you happen to have a collection of MyClass, you have to use a temporary collection:

List<MyClass> items = // your original list;  
 
var copy = new List<object>();  
items.ForEach(o => copy.Add(o));  
 
externalLib.DoSomething(copy); 

I understand that MyClass and object are different types, but why can't there be a type-safe implicit conversion towards a list of the parent type? If a method want to process a list of trees, I don't see anything wrong with giving it a list of lemon trees.

Or maybe at least a type-safe extension method?

DoSomething( items.AsList<object>() ); 

Friday, March 27, 2009 2:28 PM

It's called "genetic variance", and currently they're planning on supporting explicit covariance and contravariance.

Here's a high-level overview of what will be allowed for collection variance:

**Generic Variance in C# 4.0
**http://kohari.org/2008/10/28/generic-variance-in-c-40/

and delegate variance (note that a more limited form of delegate variance is allowed in the current language):

LINQ Farm: Covariance and Contravariance in C# 4.0
http://blogs.msdn.com/charlie/archive/2008/10/28/linq-farm-covariance-and-contravariance-in-visual-studio-2010.aspx

and, finally, a complete 11-part series of posts explaining way more than anyone needs to know at this point:

**Eric Lippert on Covariance and Contravariance
**http://blogs.msdn.com/ericlippert/archive/tags/Covariance+and+Contravariance/default.aspx

      -Steve


Friday, March 27, 2009 2:35 PM

Romain Prieto said:

Stephen, do you know how they plan on fixing this in .Net 4.0?

The C# Futures page has all this information.

http://code.msdn.microsoft.com/csharpfuture

Or maybe at least a type-safe extension method?

DoSomething( items.AsList<object>() ); 

These two methods may help.

Enumerable.OfType
Enumerable.Cast

Types with generic parameters are defined at runtime in memory with the type parameters filled in.  They're not contra-variant or co-variant. 

Arrays, however, are covariant in C#.

int[] can be cast to IList<object> and IList<int> as well.

David Morton - http://blog.davemorton.net/