5

I have the following class structure:

public class Fruit { }
public class Apple : Fruit { }

And then I am using a method from the .net framework that gets me a property value from a class returned as an object. So,

// values will be of type List<Apple>
object values = someObject.GetValue()

I now have this values object of type List and I want to cast it to a List of type Fruit. I tried the following but it didn't work.

List<Fruit> fruits = values as List<Fruit>;

Anyone know how to go about casting an object to a List of its base class?

Update: At the point of casting I don't know that the values object is of type List I just know that it should be a List of a type that inherits from Fruit.

Nick Olsen
  • 6,299
  • 11
  • 53
  • 75

3 Answers3

6

The problem is that List<Apple> and List<Fruit> are not co-variant. You'll first have to cast to List<Apple> and then use LINQ's Cast method to cast the elements to Fruit:

List<Fruit> fruits = values is List<Apple> ? 
    (values as List<Apple>).Cast<Fruit>().ToList() :
    new List<Fruit>();

If you don't know the type ahead of time and you don't need to modify the list (and you're using C# 4.0), you could try:

IEnumerable<Fruit> fruits = values as IEnumerable<Fruit>;

Or, I guess, if you need a List:

List<Fruit> fruits = (values as IEnumerable<Fruit>).ToList();
Justin Niessner
  • 242,243
  • 40
  • 408
  • 536
  • I don't know the values object is of type Apple though. I just know that it *should* be of a type that inherits the base class Fruit. – Nick Olsen Nov 11 '11 at 17:09
  • @Nick Olsen - Updated with options if you're using C# 4.0. – Justin Niessner Nov 11 '11 at 17:16
  • I am using C# 4.0 and casting it to an IEnumerable worked! Is there a reason why that is so and that it can't be cast to List? – Nick Olsen Nov 11 '11 at 17:20
  • @Nick Olsen - Long story. Start reading from Part One to Part Eleven: http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx – Justin Niessner Nov 11 '11 at 17:25
  • found a way to do this if you are passing to a method. Create a generic method. .net 4. void method(List list) where T:BaseClass{ }. that way you can pass method(list) where list is base class; – TatiOverflow Sep 28 '19 at 20:54
2

you should try linq cast method. the Cast method will return an IEnumerable of the type you are casting to...

   List<Fruit> fruits = null;
   if ( values is List<Apples> ) 
     fruits = ((List<Apples>)values).Cast< fruits >.ToList();
Muad'Dib
  • 28,542
  • 5
  • 55
  • 68
1

Since you say that you know the object is a list of fruits, but you don't know which fruit it's a list of, you can do this:

List<Fruit> fruits = ((IEnumerable)values).Cast<Fruit>().ToList();

If you're using .NET 4 (excluding Silverlight 4), you can use Justin Niessner's solution:

List<Fruit> fruits = ((IEnumerable<Fruit>)values).ToList();

Finally, it might be possible to use a generic solution, if there's a call site where the static type of the fruit (Apple or whatever) is known. This would mean changing the code quite a bit so you're no longer getting the values using reflection.

Another generic approach would be to create the generic method and construct it at run time by calling GetType() on the object, but that's probably a case of the cure being worse than the disease.

phoog
  • 42,068
  • 6
  • 79
  • 117