Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does upcasting IDictionary<TKey, TValue> to IEnumerable<object> fail?

See the following code snippet:

(IEnumerable<object>)new Dictionary<string, string>()

The above cast will throw an invalid cast exception.

Actually, IDictionary<TKey, TValue> also indirectly implements IEnumerable<out T>, because it also implements ICollection<T>. That is, the whole cast should be valid.

In fact, for me it is even more strange that if I run the whole cast on a debugger watch slot, it works!

Enter image description here

What's going on?

like image 926
Matías Fidemraizer Avatar asked Jul 18 '16 09:07

Matías Fidemraizer


3 Answers

That dictionary does implement IEnumerable<KeyValuePair<TKey, TValue>> and IEnumerable, but IEnumerable of a struct is not the same as IEnumerable of an object. Variance only works for reference-types. KeyValuePair<K, V> is a struct and not a class.

This does work at my end and should be the logical choice:

var x = (IEnumerable)new Dictionary<string, string>();

As a sample, this does work:

List<string> l = new List<string>();
var x = (IEnumerable<object>)l;

But this one doesn't:

List<DateTime> l2 = new List<DateTime>();
var x = (IEnumerable<object>)l2;

Clearly indicating the struct is the problem.

(Why it works in your Watch windows, I don't know)

like image 162
Patrick Hofman Avatar answered Sep 20 '22 21:09

Patrick Hofman


I think this is because KeyValuePair is a Value-Type.

This would fail:

List<int> ints = new List<int>();
var objs = (IEnumerable<object>)ints;

This would work:

List<string> ints = new List<string>();
var objs = (IEnumerable<object>)ints;

same goes for the dictionary.

like image 26
Zein Makki Avatar answered Sep 22 '22 21:09

Zein Makki


If you really can't live with plain IEnumerable, try this:

new Dictionary<string, string>().Cast<object>();
like image 1
Paulo Morgado Avatar answered Sep 23 '22 21:09

Paulo Morgado