When I list all the types in the current AppDomain, I see my generic types with the generic placeholders. However, if I instantiate my generic types with a type and then list al
As far as I can understand in this case Foo
is an open unbound generic type, so at runtime the CLR will use it as a blueprint/skeleton to construct and close a generic type with the type parameter type specified (Foo
, Foo
, etc.). So basically Foo
is a runtime constructed implementation of the Foo
skeleton.
Now, at run-time you can get the type of Foo
either by using typeof(Foo
or typeof(Foo<>).MakeGenericType(new[] { typeof(int) })
and it's not the same Type
and it wouldn't make sense for it to be. But look closer and you will see that both typeof(Foo
and typeof(Foo
share the same metadata token and GUID.
Another interesting thing is that typeof(Foo
will be what you would expect, but as you've noticed already you can't get that type from the Assembly.
That's because Foo
is not defined in the assembly (you can check the assembly metadata with Reflector/ILSpy). At run-time the CLR will create ("construct") a specialized ("closed") version of the Foo
for Foo
(so - constructed closed type of an unbounded open generic type definition) and "give" it a Type
. So unless the CLR exposes directly somehow the list of closed generic types it generates at run-time you are out of luck.
Also here is a snippet that might confirm what I am saying:
Even though each construction of a generic type, such as Node< Form > and Node< String >, has its own distinct type identity, the CLR is able to reuse much of the actual JIT-compiled code between the type instantiations. This drastically reduces code bloat and is possible because the various instantiations of a generic type are expanded at run time. All that exists of a constructed type at compile time is a type reference. When assemblies A and B both reference a generic type defined in a third assembly, their constructed types are expanded at run time. This means that, in addition to sharing CLR type-identities (when appropriate), type instantiations from assemblies A and B also share run-time resources such as native code and expanded metadata.
http://msdn.microsoft.com/en-us/magazine/cc163683.aspx