问题
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?
回答1:
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);
}
回答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.
来源:https://stackoverflow.com/questions/34715706/how-to-iterate-over-items-of-a-list-when-i-only-have-access-to-the-object-of-tha