views:

419

answers:

6

Everything inherits from object. It's the basis of inheritance. Everything can be implicitly cast up the inheritance tree, ie.

object me = new Person();

Therefore, following this through to its logical conclusion, a group of People would also be a group of objects:

List<Person> people = new List<Person>();
people.Add(me);
people.Add(you);
List<object> things = people; // Ooops.

Except, that won't work, the people who designed .NET either overlooked this, or there's a reason, and I'm not sure which. At least once I have run into a situation where this would have been useful, but I had to end up using a nasty hack (subclassing List just to implement a cast operator).

The question is this: is there a reason for this behaviour? Is there a simpler solution to get the desired behaviour?

For the record, I believe the situation that I wanted this sort of behaviour was a generic printing function that displayed lists of objects by calling ToString() and formatting the strings nicely.

+4  A: 

you can use linq to cast it:

IEnumerable<Person> oldList = someIenumarable;
IEnumerable<object> newList = oldlist.Cast<object>()
mattlant
Note that this is an iterative cast, and will impose a performance hit. Don't confuse the LINQ Cast<T> method with a native C# cast...the two are different.
jrista
+5  A: 

OK, everyone who has used generics in .net must have run into this at one point or another.

Yes, intuitively it should work. No, in the current version of the C# compiler it doesn't.

Eric Lippert has a really good explanation of this issue (it's in eleven parts or something and will bend you mind in places, but it's well worth the read). See here.

edit:

dug out another relevant link, this one discusses how java handles this. See here

Hamish Smith
+1  A: 

With linq extension methods you can do

IEnumerable<object> things = people.Cast<object>();
List<object> things = people.Cast<object>().ToList();

Otherwise since you are strongly typing the list the implicit conversion isn't allowed.

Quintin Robinson
+3  A: 

At first glance, this does not make intuitive sense. But it does. Look at this code:

List<Person> people = new List<Person>();
List<object> things = people; // this is not allowed
// ...
Mouse gerald = new Mouse();
things.add(gerald);

Now we suddenly have a List of Person objects... with a Mouse inside it!

This explains why the assignment of an object of type A<T> to a variable of type A<S> is not allowed, even if S is a supertype of T.

Thomas
Agreed, but wouldn't it be nice to have the same facilities as in the java generics where you can specify 'T ? super MyClass'?
Hamish Smith
You could always get around this problem by ie, marking the casted list readonly, but your point is well taken.
Matthew Scharley
I did not understand your reasoning....
Luis Filipe
Then try the explanation by Eric Lippert, mentioned in the Accepted Answer. It goes into all the details.
Thomas
+3  A: 

The linq workaround is a good one. Another workaround, since you are using type object, is to pass the list as IEnumerable (not the generic version).

Edit: C# 4 (currently beta) supports a covariant type parameter in IEnumerable. While you won't be able to assign directly to a List<object>, you can pass your list to a method expecting an IEnumerable<object>.

dcstraw
+2  A: 

While what your trying to does indeed flow logically, its actually a feature that many languages don't natively support. This is whats called co/contra variance, which has to do with when and how objects can be implicitly cast from one thing to nother by a compiler. Thankfully, C# 4.0 will bring covariance and contravariance to the C# arena, and such implicit casts like this should be possible.

For a detailed explanation of this, the following Channel9 video should be helpful:

http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/

jrista