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 removedAnonymous
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 C
1+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.