Nathan A
Nathan A

Reputation: 11319

Upcasting Generics

Ok, I know this is impossible, but I'm wondering if anyone knows of a way to get around this.

List<int> numberList = new List<int>();

List<object> objectList = (List<object>)numberList;

This generates the following error:

Cannot convert type 'System.Collections.Generic.List{int}' to 'System.Collections.Generic.List{object}'

This is a simple example, but here is my real problem. I have a method that dynamically generates an IQueryable{IGrouping{TKey, TElement}} instance. However, since in my case TKey is dynamically generated, I can only return an IQueryable to the caller.

I want to be able to return an IQueryable{IGrouping{dynamic, TElement}} to the caller. However, the compiler complains because just like in my first example, its casting TKey as an object (for dynamic), and won't let me cast it that way. Is there any way around that?

Update:

Here is a closer example of what I'm trying to solve:

List<int> testList = new List<int>();

var qry = new EnumerableQuery<int>( testList );

var objectQry = (IQueryable<object>)qry;

While this example doesn't produce a compile-time error, is does produce a casting exception when you try to run it. For some reason, even though IQuerable is covariant (thanks Servy for your comments on that), once I introduce an implementing class such as EnumerableQuery, it fails.

Upvotes: 3

Views: 1041

Answers (2)

Servy
Servy

Reputation: 203821

You need to construct a copy of each new dictionary, because dictionaries as well as lists are not covariant with respect to any of their generic arguments.

(The keys are also provided in output through the Keys property, and the sequence of pairs itself, so even IDictionary<TKey, TValue> cannot be covariant with respect to TKey.)

You can use Select to map each object to a new object:

List<Dictionary<int, string>> listOfDicts = new List<Dictionary<int, string>>();
List<Dictionary<object, string>> newList = listOfDicts.Select(dic =>
        dic.ToDictionary(pair => (object)pair.Key, pair => pair.Value))
    .ToList();

IQueryable<T> on the other hand is covariant, as is IGrouping, so you can cast interfaces of those types up:

IQueryable<IGrouping<dynamic, int>> query = null;
IQueryable<IGrouping<object, int>> otherQuery = query;

That compiles and runs just fine.

Upvotes: 2

Ryan T. Grimm
Ryan T. Grimm

Reputation: 1325

Try this.

List<int> numberList = new List<int>();
List<object> objectList = numberList.Cast<object>().ToList();

Enumerable.Cast<T>

Casts the elements of an IEnumerable to the specified type.

Upvotes: 3

Related Questions