locked
Casting of generic type with unknown type parameter

    Question

  • Hi guys and gal,

    I got an issue trying to cast an object, into a generic type with an unknown type parameter.  The following an example:

    Code Snippet

        public class BaseClass
        {}

        public class DerivedClass : BaseClass
        {}

        public class GrandDerivedClass : DerivedClass
        {}

        public class MyParam<T> where T : BaseClass
        {
            public MyParam(T input)
            {}
        }

        public class Service
        {
            public static void doSomething<T>(T param)
                where T : BaseClass
            {
                // do something


                Type typeLoop = typeof(T);


                while (typeLoop.BaseType != typeof(BaseClass))
                {
                    Type generic = typeof(MyParam<>);

                    Type[] typeArgs = { typeLoop.BaseType };

                    Type constructed =
                        generic.MakeGenericType(typeArgs);

                    ConstructorInfo ctor =
                        constructed.GetConstructor(
                            typeArgs);

                    object arg =
                        ctor.Invoke(new object[] { param });

                    doSomethingElse(
                        (MyParam<typeLoop.BaseType>)arg);     // CAN'T DO THIS!!!!


                    typeLoop = typeLoop.BaseType;

                }
            }

            private static void doSomethingElse<U>(MyParam<U> param)
                where U : BaseClass
            {
               
            }
        }



    So i'm just trying to do a cast from a generic type where the type parameter is unknown at compile time.  I need to do this because I don't know how many level of hirerchy there is, but I have to do something on each level.  So if I do something like:

    Code Snippet

    doSomethingElse((MyParm<BaseType>)arg;



    this will just get me the single level at the very root.  Any idea how I can do this cast?

    Thanks!  Any help would be much appreciated!

    William
    Thursday, August 09, 2007 1:17 AM

Answers

All replies

  • You can't do what you want, Generics aren't covariant.  Which means you can't cast one generic type to another despite their parameterized type deriving from the same base.  For example:

     

    Code Snippet

    public class Base {}
    public class Derived1 : Base {}
    public class Derived2 : Base {}
    public class G1<T> {}
    //...

      G1<Derived1> g1d = new G1<Derived1>();
      G1<Base> g1b = (G1<Base>)g1d; // error CS0030

     

     

    For more information on why Generics aren't covariant and why they never will be is detailed here: http://msdn2.microsoft.com/en-gb/library/aa479859.aspx#fundamentals_topic12

    Thursday, August 09, 2007 1:35 AM
    Moderator
  • Hi Peter,

    Yes I know the generic types are not covariant, but the type parameter in the generic are.  So I'm just relying on that when casting, as from my example:

    Code Snippet

    doSomethingElse( (MyParam< typeof(T).BaseType >) arg);



    My college pointed out that at the end of the day, I'm really doing something like:

    Code Snippet

    doSomethingElse( (constructed) arg);



    where I'm trying to cast a variable from a Type object instance.  Cause if you look at where I define "constructed" in the sample code, I do have a Type reference to "MyParam<typeof(T).BaseType>" already.  It's just a matter of casting it.

    William
    Thursday, August 09, 2007 1:47 AM
  • You might be able to do something with Type.MakeGenericType but you're not going to be able to do the compile-time cast.

     

    Thursday, August 09, 2007 4:57 AM
    Moderator