Sonali Gogate
The CLR loader manages application domains. This involves loading the
assemblies into appropriate domains and managing the memory layout of the type
hierarchy. Assemblies contain modules, modules contain types, and types contain
members. Reflection provides objects that encapsulate assemblies, modules, and
types.
Some of the things that Reflection can be used for are —
- Use assembly to define and load assemblies, load modules defined in the
assemblies manifest, locate types defined in the assembly and create
instances of that type.
- Use module to get information such as the assembly in which this module is
defined in, the classes in the module as also global methods defined in the
module.
Reflection APIs
The classes and APIs one would need for reflection are defined in the System.Reflection
namespace of the .NET framework. There are different classes in this namespace
specific to assembly, module, fields etc access. These classes encompass a whole
lot of functionality and help is available on all of them.
The System.Type class is at the center of Reflection mechanism. This is an
abstract class, representing a type in the CTS and it enables you to query for a
type’s metadata, like name, module and namespace.
Here is how you would retrieve a type object —
using System; using System.Reflection; class RetrieveTypeSample { public static void Main(string<> args) { string assembyName = args<0>; Type t = assemblyName.GetType(); Console.WriteLine(t.Name); } }
You can also create a Type object from a type name (that is without an instance
of the type being present.
Here is an example —
using System; using System.Reflection; class TypeObjectFromNameSample { public static void Main(string<> args) { Type t = Type.GetType("System.Int32"); Console.WriteLine(t.Name); } }
To build types as runtime, you need to use System.Reflection.Emit namespace.
One can use MemberInfo, MethodInfo, FieldInfo, and PropertyInfo to get
information about type’s methods, properties, events and fields.
Assemblies & Modules
Using Assembly class we can —
- List the modules of the assembly
- Iterate through its types
- Get assembly’s name and physical location
- Get versioning and security information
Here is sample code to iterate through the types of an Assembly —
class GetTypesinmyApp { static string GetAssemblyName(string<> args) { string assemblyName; if (0 == args.Length) { Process cp = Process.GetCurrentProcess(); assemblyName = cp.ProcessName + ".exe"; } else { assemblyName = args<0>; } return assemblyName; } public static void Main(string<> args) { string assemblyName = GetAssemblyName(args); Assembly asmbl = Assembly.LoadFrom(assemblyName); Console.WriteLine(“\n Assembly is: “ + asmbl); Type<> types = asmbl.GetTypes(); foreach(Type t in types) { Console.WriteLine(“\n Type Name: “+ t.FullName); } } }
Dynamic code generation through Reflection
Creating code at run time can be done using the System.Reflection.Emit
namespace. Using the classes in this namespace, an assembly can be defined in
the memory, a module can be created for that assembly, new types can be defined
for a module (including its members), and MSIL opcodes for the application's
logic can be emitted.
And here is some sample code that can be used to generate code on the fly —
// We would need to be using the following namespaces — using System; using System.Reflection; using System.Reflection.Emit; //Define the namespace and class etc ... namespace DynCodeGen { Class CodeGenerator { AppDomain currentDomain; AssemblyName aName; AssemblyBuilder assemblyBuilder; ModuleBuilder moduleBuilder; TypeBuilder typeBuilder; MethodBuilder methodBuilder; ILGenerator msilG; object o; Type t; public CodeGenerator() { // Get currentDomain. currentDomain = AppDomain.CurrentDomain; // Create assembly aName = new AssemblyName(); aName.Name = "MyAssembly"; assemblyBuilder = currentDomain.DefineDynamicAssembly (aName, AssemblyBuilderAccess.Run); // create a module moduleBuilder = assemblyBuilder.DefineDynamicModule("MyModule"); // create a type typeBuilder = moduleBuilder.DefineType ("MyClass",TypeAttributes.Public); // add a member (method) to the type methodBuilder = typeBuilder.DefineMethod ("HelloWorld", MethodAttributes.Public, null,null); // Generate MSIL. msilG = methodBuilder.GetILGenerator(); msilG.EmitWriteLine("Hello World"); msilG.Emit(OpCodes.Ret); // create type. t = typeBuilder.CreateType(); } public Type T { get { return this.t; } } } }
To use this code generator to generate dynamic code, we would do some like this —
public static void Main() { CodeGenerator gen = new CodeGenerator(); Type t = gen.T; if (null != t) { object o = Activator.CreateInstance(t); MethodInfo helloWorld = t.GetMethod("HelloWorld"); if (null != helloWorld) { helloWorld.Invoke(o, null); } else { Console.WriteLine("Error in method name"); } } else { Console.WriteLine("Erroraccessing Type"); } }
There is a lot more to Reflection and it’s a very powerful feature. This is
just an introduction and a starting point.