Welcome to weblogs.com.pk Sign in | Join | Help

Nasir Ali Khan

Believing is easier than thinking. Hence so many more believers than thinkers.
A Developers Introduction to Dynamic Assemblies
Intended Readers: Persons having basic knowledge of assemblies, IL, meta data.
Platform
: .NET 1.1

Level
: Intermediate


Introduction

Assembly is a basic deployment unit in .NET framework it contains types, resources code etc. Assemblies can be classified into two types static and dynamic. Static assemblies are the normal assemblies build by the .NET enabled compilers and other tool such is al (Assembly Linker).  Once build static assemblies cannot be changed although we can dynamically loads them or create type from them but still their nature is static.

Dynamic assemblies are build at runtime and we can add the contents dynamically or alter the existing one or can also emit the IL code directly in assembly, normally this happens in the memory but in the end we can also persist the dynamic assembly as well. .NET framework provides all these services in System.Reflection.Emit namespace. System.Reflection.Emit contains various builder classes which provide abstract access for the code emition. For example TypeBuilder class is used to dynamically defining the type; AssemblyBuilder is used for building and persisting the dynamic assembly etc.

Dynamic Assemblies in Action
Lets look an example in which following type will generate by the program through System.Reflection.Emit classes
class MyDynamicType
{
      public MyDynamicType()
      {
            Console.WriteLine("Constructor Called");
      }
      public void MyMethod()
      {
            Console.WriteLine("Method Called");
      }
}


First step
is to create the dynamic instance of assembly, this can be done through AppDomain.DefineDynamicAssembly () i.e.

AssemblyName asmname = new AssemblyName();
asmname.Name = "DynAsm.dll";
// Dynamic assembly supports dynamic execution and persistence
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmname, AssemblyBuilderAccess.RunAndSave);


AssemblyName
class provides the access for various features of assembly such as KeyPair, Culture.
Second step is to create the dynamic module which in turns responsible for creating dynamic types.

// name of module and assembly
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("MyModule", "MyAsm.dll");
// defining the public type
TypeBuilder typeBuilder = modBuilder.DefineType("MyDynamicType", TypeAttributes.Public);

After getting the reference of typeBuilder we can add members in it i.e.

// zero arg constructor for new type
ConstructorBuilder defctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]);


Then comes the important task generation of actual IL code, this can be done through ILGenerator interface (which emits the actual IL Code), i.e.

ILGenerator ctorIlGen = defctor.GetILGenerator();
// Console.WriteLine(...)
ctorIlGen.EmitWriteLine("Constructor Called");
// emit Return statements
ctorIlGen.Emit(OpCodes.Ret);


OpCodes enum
represents the IL opcodes such as method call, load string, method return etc. Detail knowledge of all IL opcodes can be found at MSDN.

The above process will remains same for all methods, after emiting the IL its time to Emit the IL code and dynamically calls it, typeBuilder.CreateType() is responsible for emiting the underlying IL code and returns the Type object.

Type t = typeBuilder.CreateType();
// create the object instance from the Type
object obj = Activator.CreateInstance(t);
// its time to save all the work in Assembly
asmBuilder.Save("MyAsm.dll");

The complete code of above process is

AssemblyName name = new AssemblyName();
name.Name = "MyAsm";
 
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndSave);
 
// Get Module Builder
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("MyModule", "MyAsm.dll");
      // Get Type Builder
      TypeBuilder typeBuilder = modBuilder.DefineType("MyDynamicType", TypeAttributes.Public);
            // zero arg constructor
            ConstructorBuilder defctor = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[0]);
                  ILGenerator ctorIlGen = defctor.GetILGenerator();
                        ctorIlGen.EmitWriteLine("Constructor Called");
                        ctorIlGen.Emit(OpCodes.Ret);
           
            MethodBuilder mBuilder = typeBuilder.DefineMethod("MyMethod", MethodAttributes.Public, typeof(void), new Type[0]);
                  ILGenerator ilgen = mBuilder.GetILGenerator();
                        ilgen.EmitWriteLine("Method Called");
                        ilgen.Emit(OpCodes.Ret);
      Type t = typeBuilder.CreateType();
 
object obj = Activator.CreateInstance(t);
// invoke the obj.mymethod()
t.InvokeMember("MyMethod", BindingFlags.InvokeMethod, null, obj, null);
asmBuilder.Save("MyAsm.dll");

Once the assembly is generate you can use it in other applications

Advantages of Dynamic Assemblies

  • Dynamic Assemblies provides great flexibility for developers
  • Primarily used by assembly generation tools, script engines and compiler vendors
  • We can create new .NET languages with different specifications and syntax.
  • Directly emiting IL means we are bypassing the specifications and limitations of existing languages results efficient IL code.
  • Generate types and code as needed, which can results efficient downloading of assemblies from network locations.

Your Comments and Feedbacks are always welcome

Posted: Saturday, September 17, 2005 2:38 AM by nasir

Comments

No Comments

Anonymous comments are disabled