问题
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.
回答1:
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
回答2:
you can use linq to cast it:
IEnumerable<Person> oldList = someIenumarable;
IEnumerable<object> newList = oldlist.Cast<object>()
回答3:
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.
回答4:
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>.
回答5:
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/
回答6:
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.
来源:https://stackoverflow.com/questions/110121/logic-and-its-application-to-collections-generic-and-inheritance