[Mono-list] Collections of generic objects: IDictionary casting problem

Jonathan Pryor jonpryor at vt.edu
Sat Dec 9 15:47:38 EST 2006


On Wed, 2006-12-06 at 12:56 +0100, Generic 2006 wrote:
> I have a problem casting collections of generic objects.

Here's the short version: the following is not currently possible with
Generics:

	class Base {}
	class Derived : Base {}
	...

	IEnumerable<Derived> d = null;
	IEnumerable<Base> b = d;	// error

You'd *like* this to work, but it can't, it subverts the type system:

	List<string> ls = new List<string> ();

	// the following is currently an error; you want this to 
	// be valid
	List<object> lo = ls;

	lo.Add ((object) 42);	// oops!

Generics are supposed to make code safe, so that you don't get
TypeCastExceptions, but the above can't work -- you can't add an int to
a List<string>.

You're trying to do the same thing, just with more indirection:

>  {
>   IDictionary<String,Wrapper<InnerType>> types;
>    /*
>     The following assignment throws a compile-time exception:
> 
> error CS0266: Cannot implicitly convert type
> 'System.Collections.Generic.IDictionary<System.String,OuterType1>' to
> 'System.Collections.Generic.IDictionary<System.String,Wrapper<InnerType>>'.
> An explicit conversion exists (are you missing a cast?)

OuterType1 : Wrapper<InnerSubType1>, which is compatible with
Wrapper<InnerType>, but this is *exactly* the scenario I described above
with trying to assign a List<string> to a List<object> (string derives
from object) or assigning a IEnumerable<Derived> to an
IEnumerable<Base>.  You can't do that.

Now, there are ways to specify in IL that such conversions are possible
-- iirc these are known as Covariant generic types (or something like
that) -- but C# has no way to express this.  (AFAIK, at present only IL
can express this.)

You'll have to modify your code to work around this limitation.

 - Jon




More information about the Mono-list mailing list