How to iterate over items of a list when I only have access to the object of that list and dont know the type parameter?
Asked Answered
A

2

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?

Appling answered 11/1, 2016 at 6:53 Comment(8)
what is the type of dataModel.Value ?Anode
Does it work if you case to IEnumerable<Object>?Fealty
What about #633070? Try using IList.Adrenalin
Why do you want to cast it?? It should work just fine with foreach (object item in dataModel.Value) shouldn't it?Phrixus
@FrebinFrancis dataModel.Value is a list. But I don't know type of items in that list.Appling
@VikasGupta - That would only work if dataModel.Value is declared as a list. If it's declared as object your suggestion wouldn't work.Fealty
@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.Fealty
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 assemblyAppling
P
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);
}
Perron answered 11/1, 2016 at 7:2 Comment(0)
G
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.
Goodhen answered 11/1, 2016 at 7:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.