Udostępnij za pośrednictwem


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

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;<br> <br>class Program<br>{<br>    static void Main()<br>    {<br>        Action<C<int>.E> a = M;<br>        var open = a.Method.GetGenericMethodDefinition().GetParameters()[0].DefaultValue;<br>        Console.WriteLine(open.GetType());<br>    }<br> <br>    static void M<T>(C<T>.E e = 0) { }<br>}<br> <br>class C<T><br>{<br>    public enum E { }<br>}

Comments

  • Anonymous
    January 08, 2014
    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.

  • Anonymous
    January 08, 2014
    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 :)

  • Anonymous
    January 10, 2014
    The comment has been removed

  • Anonymous
    January 10, 2014
    Console.WriteLine-ing the types gives the same answer for both; however, dumping the types with WinDbg gives open1 as C1+E and open2 as type C1+E[T]. Weird stuff!

  • Anonymous
    January 11, 2014
    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.