Q:

How does Reflection work on a machine language level

I know reflection is done by "reading the metadata", but when it is compiled, how is it stored? Additionally, how much space gets taken up from the metadata? If a decompiler can regenerate my entire c# program from the metadata, is it storing almost as much metadata as written code?

A:

You can see the metadata if you open an assembly using ildasm.  You will see the list of classes, the attributes applied to the classes, referenced DLLs, the methods and signatures, ...  You would have to read the specifications of the .dll format for .NET executables to see exactly how much space it takes up and All of that is stored in the assembly in a more compact format than the assembly.
Then can then click on a method and you will see the code, compiled into intermediate language.  You will notice it is quite different from your source code.  A decompiler such as the free ilspy can't regenerate the C# program exactly as your wrote it.  The generated IL is not as low-level as say, x86 assembly, but it is high enough level that a decompiler can do a pretty good job though.  Enough that you can probably understand what the code was doing.
There are some other questions on stack overflow covering this topic.
What are the `exact` differences between .NET dll and a normal dll?
Also try some searches on the "Portable Executable" AKA PE format.
http://www.codeproject.com/Articles/12585/The-NET-File-Format
I'm not so sure about how much actual storage size it is.  You would have to dig into the format to see.  Or try compiling some code and compare the code size to the executable size.

