0

Somewhere in my code I have an object that I already know that is a list. But I don't know the type parameter of that list. I need to iterate over it's items. I tried to cast that object to a list of objects but it didn't help me:

List<Object> objList = (List<Object>)(dataModel.Value);
foreach (var item in objList)
{
        Console.WriteLine(item.ToString());
}

In the above code, the Value property of dataModel is a list of XYZ values, but it throws an exception when I run this code. It says that, it could not cast XYZ to Object.

Is that possible to do some deserialization and do the job over deserialized objects?

a.toraby
  • 3,232
  • 5
  • 41
  • 73
  • what is the type of dataModel.Value ? – Frebin Francis Jan 11 '16 at 06:56
  • 1
    Does it work if you case to `IEnumerable`? – Enigmativity Jan 11 '16 at 06:56
  • 1
    What about http://stackoverflow.com/questions/632570/cast-received-object-to-a-listobject-or-ienumerableobject? Try using `IList`. – Dovydas Šopa Jan 11 '16 at 06:57
  • 1
    Why do you want to cast it?? It should work just fine with `foreach (object item in dataModel.Value)` shouldn't it? – Jakob Olsen Jan 11 '16 at 06:59
  • @FrebinFrancis `dataModel.Value` is a list. But I don't know type of items in that list. – a.toraby Jan 11 '16 at 07:00
  • @VikasGupta - That would only work if `dataModel.Value` is declared as a list. If it's declared as `object` your suggestion wouldn't work. – Enigmativity Jan 11 '16 at 07:23
  • @VikasGupta - Of course it is a list, but `dataModel.Value` is obviously not declared as a list - if it were the OP wouldn't have needed to cast it in the first place. – Enigmativity Jan 11 '16 at 07:53
  • In my application I obtained `datamodel.Value` from another assembly using reflection. I extract `FieldInfo` of all items in runtime, but in compile time I do not have access to the type parameters, because I have reflected the `dataModel` from an external assembly – a.toraby Jan 11 '16 at 07:59

2 Answers2

5

You should cast to IEnumerable<object>, or even just IEnumerable.

A List<string> is not a List<object> as generic variance doesn't apply to classes, and a List<string> is not an IList<object> as IList<T> is not covariant. (It can't be, due to operations which accept a T, such as Add.)

However, IEnumerable<T> is covariant in T which is exactly what you want in this case - but only if your value is a list of reference types; covariance doesn't work with type arguments which are value types... so a List<int> isn't convertible to IEnumerable<object>. It is still convertible to IEnumerable though, so the following code gives you the most flexible solution:

var items = (IEnumerable) dataModel.Value;
foreach (var item in items)
{
    Console.WriteLine(item);
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
2

A List<Something> does not derive from List<object> it derives from object but not from List<object>, this makes sense as it could be very type unsafe. You can always treat a List<int> as an object for example, but if you could treat it as a List<object> you could then call .Add("test") and end up with a List<int> containing a string violating type safety.

However recent .net versions added covariance and contravariance, it doesn't make sense on List<T> but it DOES make sense on IEnumerable<T> (as you can't "add" to an IEnumerable but only enumerate it, it's very fine to enumerate items of arbitrary types as objects).

So you can cast to the interface:

IEnumerable<Object> objList = (IEnumerable<Object>)(dataModel.Value); // This works, List<whatever> is IEnumerable<whatever>, IEnumerable<whatever> can safely be cast to IEnumerable<object>

Or you can cast the individual items themselves if you want to stick to a List by creating a new List as such:

List<object> objlist = dataModel.Value
     .Cast<object>() // every item will be cast to object
     .ToList(); // then make a new list out of it, this is type safe as the original List<whatever> is not affected.
Ronan Thibaudau
  • 3,413
  • 3
  • 29
  • 78