Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't I cast from a List<MyClass> to List<object>?

I have a List of objects, which are of my type QuoteHeader and I want to pass this list as a list of objects to a method which is able to accept a List<object>.

My line of code reads...

Tools.MyMethod((List<object>)MyListOfQuoteHeaders);

But I get the following error at design time...

Cannot convert type 'System.Collections.Generic.List<MyNameSpace.QuoteHeader>' 
to 'System.Collections.Generic.List<object>'

Do I need to do anything to my class to allow this? I thought that all classes inherit from object so I can't understand why this wouldn't work?

like image 578
Karl Avatar asked May 04 '11 10:05

Karl


People also ask

Can we convert list string to list object?

The constructor takes a Collection , but List is a subinterface of Collection , so you can just use the List<String> . This constructs unnecessary objects and can, if this is a big list, potentially take up a lot of memory. Just cast it.

Can object be cast to list?

you can always cast any object to any type by up-casting it to Object first. in your case: (List<Customer>)(Object)list; you must be sure that at runtime the list contains nothing but Customer objects.

How do you write a cast list in Java?

Try the following: List<TestA> result = new List<TestA>(); List<TestB> data = new List<TestB>(); result. addAll(data);


2 Answers

The reason this is not legal is because it is not safe. Suppose it were legal:

List<Giraffe> giraffes = new List<Giraffe>(); List<Animal> animals = giraffes; // this is not legal; suppose it were. animals.Add(new Tiger());  // it is always legal to put a tiger in a list of animals 

But "animals" is actually a list of giraffes; you can't put a tiger in a list of giraffes.

In C# this is, unfortunately, legal with arrays of reference type:

Giraffe[] giraffes = new Giraffe[10]; Animal[] animals = giraffes; // legal! But dangerous because... animals[0] = new Tiger(); // ...this fails at runtime! 

In C# 4 this is legal on IEnumerable but not IList:

List<Giraffe> giraffes = new List<Giraffe>(); IEnumerable<Animal> animals = giraffes; // Legal in C# 4 foreach(Animal animal in animals) { } // Every giraffe is an animal, so this is safe 

It is safe because IEnumerable<T> does not expose any method that takes in a T.

To solve your problem you can:

  • Create a new list of objects out of the old list.
  • Make the method take an object[] rather than a List<object>, and use unsafe array covariance.
  • Make the method generic, so it takes a List<T>
  • Make the method take IEnumerable
  • Make the method take IEnumerable<object> and use C# 4.
like image 131
Eric Lippert Avatar answered Sep 19 '22 12:09

Eric Lippert


You can't cast List<OneType> to List<OtherType> as it is actually the instances of the list you want to cast, as well as the List itself.

there is an extension method which will allow you to do this (MSDN reference):

IEnumerable<Object> myNewEnumerable = myEnumerable.Cast<Object>();

This method will attempt to cast each instance of the list of one type to the other type and add them to a new enumerable. it will throw an exception if any instance can't be cast.

As far as the system is concerned the two types for your lists are just different types, so it is like saying:

A objectOfTypeA;
B objectOfTypeB = (B) objectofTypeA;

To be able to do the cast there would have to be an implicit or explicit conversion between the types available, which there isn't (unless you provided one, which you might be able to do).

you expect it to work because List<object> will always be able to hold any type in another list, but when you think about it in those terms you can see why it doesn't.

I'm sure there is a more technically competent answer, but that is the gist of it I think.

you might be interested in reading Eric Lippert's series on Covariance and Contravariance as this may be helpful to you.

This question may also be useful

like image 32
Sam Holder Avatar answered Sep 21 '22 12:09

Sam Holder