Creating an instance of an open generic type without specifying a type argument

Creating an instance of an open generic type without specifying a type argument

Rate This
  • Comments 5

My fellow Roslyn tester @vreshetnikov has found not one, but two ways to do the impossible:

1:

using System;
 
class Program
{
    static void Main()
    {
        var open = Enum.ToObject(typeof(C<>.E), 0);
        Console.WriteLine(open.GetType());
    }
}
 
class C<T>
{
    public enum E { }
}

2:

using System;
 
class Program
{
    static void Main()
    {
        Action<C<int>.E> a = M;
        var open = a.Method.GetGenericMethodDefinition().GetParameters()[0].DefaultValue;
        Console.WriteLine(open.GetType());
    }
 
    static void M<T>(C<T>.E e = 0) { }
}
 
class C<T>
{
    public enum E { }
}
  • Arguably those 2 ways aren't really different, it's same trick with 2 different hats :). They both rely on the enum inside the generic type and it's that enum who manages to "create" such instances, the rest of the code just exposes that.

  • This is fun, turns out that the second way doesn't actually create an instance of an open type, at least that's what IsGenericTypeDefinition claims:

    using System;

    class Program

    {

       static void Main()

       {

           var open1 = Enum.ToObject(typeof(C<>.E), 0);

           Console.WriteLine(open1.GetType().IsGenericTypeDefinition);

           Action<C<int>.E> a = M;

           var open2 = a.Method.GetGenericMethodDefinition().GetParameters()[0].DefaultValue;

           Console.WriteLine(open2.GetType().IsGenericTypeDefinition);

           Console.WriteLine(open1.GetType() == open2.GetType());

           Console.WriteLine(open1.Equals(open2));

       }

       static void M<T>(C<T>.E e = 0) { }

    }

    class C<T>

    {

       public enum E { }

    }

    This prints True, False, False, False. The type you get via the second way isn't open and it's not even equal to the type you get the first way. It would have been even more funny if the Equals returned true :)

  • @Mike: your second comment proves that these must be different tricks, since you obtain objects with very different types!

    What does open2 give for it's type argument then? It must be open since none has been specified!

    Wow, amazing testing.

  • Console.WriteLine-ing the types gives the same answer for both; however, dumping the types with WinDbg gives open1 as

    C`1+E and open2 as type C`1+E[T].

    Weird stuff!

  • They have different type parameters as their type arguments (one from C`1+E type declaration and the other from method M). You can rename one of the type parameters to see the difference.

Page 1 of 1 (5 items)
Leave a Comment
  • Please add 3 and 8 and type the answer here:
  • Post