A C# program compiles to a DLL assembly that contains the compiled C# code along with the metadata for the runtime, and other resources. C# provides a reflection API that lets us inspect the metadata and compiled code at runtime.
Using reflection, it's possible to −
Access the assembly metadata for all types inside the assembly
Obtain a list of types and their members (methods, properties, etc.)
Dynamically invoke the type members at runtime.
Instantiate objects by only providing their name
In a traditional program, when you compile the source code to the machine code, the compiler removes all the metadata about the code. However, since C# is a managed language that runs in Common Language Runtime (CLR), the compiler keeps most of the information about the code. Reflection allows us to examine the metadata within an assembly.
The System.Reflection namespace contains all the classes and other types required for reflection. You can also create new metadata and emit executable code in the Intermediate Language (IL) via the types in the System.Reflection.Emit namespace.
System.Type gives you access to a type's metadata. This object also includes methods for enumerating the type instance's members, which you can invoke.
using System; using System.Text; using System.Reflection; var sb = new StringBuilder(); // Type at runtime Type t1 = sb.GetType(); Console.WriteLine(t1.FullName); // System.Text.StringBuilder // Type at compile-time Type t2 = typeof (StringBuilder); Console.WriteLine(t2.FullName); // System.Text.StringBuilder
It's also possible to fetch a type by name, given a reference to an assembly. The following example uses the current assembly and gets the type of the Person class defined in the Models namespace.
Type personType = Assembly.GetExecutingAssembly().GetType("CSharp.Models.Person"); Console.WriteLine(personType.FullName); // CSharp.Models.Person
The Type class has a few useful properties that you can use to access the type's name, assembly, visibility, base types, etc.
using System; using System.Text; using System.Reflection; var sb = new StringBuilder(); // Type at runtime Type t1 = sb.GetType(); // What's the type's name? Console.WriteLine(t1.FullName); // System.Text.StringBuilder // What's the type's base type? Console.WriteLine(t1.BaseType); // System.Object // Which assembly is the type defined in? Console.WriteLine(t1.Assembly); // System.Private.CoreLib, Version=188.8.131.52, Culture=neutral, PublicKeyToken=7cec85d7bea7798e // Is the type public? Console.WriteLine(t1.IsPublic); // True
Along with these properties, there are methods such as GetProperties(), GetMethods(), and GetFields() that provide access to the type's members. The important thing is to obtain a reference to the type's Type object. There are two ways to achieve this −
All types include this function. It returns the type at runtime
This expression gets the type at compile-time. It binds at compile-time to a particular Type instance and it directly takes a type as a parameter.
The classes in the System.Reflection namespace along with the classes defined in the System.Type namespace allow you to obtain information about the assemblies and the types within them, e.g. classes, interfaces, and value types.