System.Reflection is a high-level way of describing Types in .NET targetted at managed code consumers. The API is easy to use, but does not expose all the information that’s actually present and affecting decisions.
For example, Reflection does not expose TypeRef, MemberRef, AssemblyRef, or other Ref tokens. These tokens are references to things in other assemblies. Reflection just resolves them for you (potentially invoking an event to get help from your app) and hands back the resolved object.
Similarly, reflection is also missing TypeSpecs. TypeSpecs are just binary signature blobs that describe compound types (arrays, generics, etc). Reflection will parse the blob and resolve it to a real System.Type.
This entry is not a complete list of all things missing in reflection; nor am I going to get into the other problems in reflection here. For now, I’ll just look at TypeRefs…
Imagine you have a class that inherits from a type in another assembly. At the metadata level, the base type is described with a TypeRef token.
1. Practically, that means you could use reflection to inspect what a base type actually bound to, but not what it was supposed to bind to (as described in the original assemblyRef).
2. Another issue is that when you have a high-level API (Reflection) that loses information over a low level API (IMetadataImport), you risk that the high-level API won’t be able to talk to the low level API because it may not be able to provide it with the information the low level API requests.
3. In related trivia, ILDasm can print TypeRef, TypeSpec tokens:
//000010: Console.WriteLine(“Hi!” + arg);
IL_0001: ldstr “Hi!” /* 70000001 */
IL_0007: call string [mscorlib/*23000001*/]System.String/*01000012*/::Concat(string,
string) /* 0A000010 */
IL_000c: call void [mscorlib/*23000001*/]System.Console/*01000013*/::WriteLine(string) /* 0A000011 */
So the inability to get the raw unresolved tokens from Reflection would prevent you from writing ILDasm on reflection that could print the above snippet.