Home / Articles / Programming Languages / C# / C# Emitting Metadata

“Chishiki” is Japanese for “knowledge.” e-chishiki.com aims to bring software developers, information security professionals, IT executives and other IT pros a rich body of knowledge in the form of articles, interviews, tutorials and technical discussions. Our contributors are among the biggest names in the Indian IT industry and include noted authors, educators and practitioners.

C# Programming Series

C# Emitting Metadata

Yashavant Kanetkar
Yashavant Kanetkar

Reflection is generally used for three purposes: viewing metadata, type discovery and invoking methods. However, the most powerful use of Reflection is emitting metadata to assembly. Reflection emits support creation of types at run-time. For emitting metadata, .NET has provided the Reflection.Emit namespace.

Reflection.Emit

Reflection emits enable creation of dynamic module defined in a dynamic assembly. A dynamic module created in a dynamic assembly can be transient or persistable.

When I first read about Reflection emit the first question came to my mind is that where on earth would I need to write metadata to an assembly when the compiler does it for us? I found few application scenarios where the applications use Reflection emit. Some of them are executing a script in a web browser, executing a script in an ASP.NET Page, compiling a Regular Expression, etc. Let us discuss these scenarios in brief.

When a web browser requests for an HTML page containing a script program the web browser first launches the script engine. Then it extracts the script from the HTML page and passes it to the script engine. The script engine creates a dynamic assembly by writing metadata on the fly. The script engine uses the Reflection emit functions to emit the code into the dynamic assembly.

In the second scenario, a browser opens an ASP.NET page containing a script program. The program is compiled on the server and executed. For this, ASP.NET launches the script engine to compile and execute the program. The script engine creates a persistable dynamic assembly and a dynamic module in it. It compiles the program using the reflection emit functions and emits the code into the persistable dynamic module. The compiled code is then executed. If any expression is encountered the script engine creates a transient dynamic module in the dynamic assembly to contain the code for the expression. The script engine evaluates the expression by executing the transient dynamic module. ASP.NET requests the script engine to save the dynamic assembly and the persistable dynamic module in the cache so that the script does not need to be recompiled when the page is visited again.

In the third scenario, a compiler uses Reflection emit to compile regular expressions in source code. The compiler processes the first use of a regular expression in a user’s source code. The compiler compiles the regular expression into a custom scanner class using reflection emits. The regular expression is first translated to the compiler’s regular expression bytecodes. For example, one instruction might say, “try to match zero or more a’s.” The regular expression byte codes are then translated to Microsoft intermediate language (MSIL). For example, the compiler might generate a loop that iterates over all the occurrences of the letter 'a' that it found. The compiler saves the compiled scanner class for future use. Whenever a subsequent expression is encountered, the compiler instantiates the compiled scanner class and executes the code.

In this article we would create a type called sample at run-time and store it in an assembly. The class has a method fun( ) that outputs a string “Hello” on console. Here is the source code.

static void Main ( string[ ] args )
{ 
       AssemblyName an = new AssemblyName( ) ;
       an.Name = "emitassembly" ;

       AppDomain ad = Thread.GetDomain( ) ;
       AssemblyBuilder ab = ad.DefineDynamicAssembly ( an, AssemblyBuilderAccess.Save ) ;

       ModuleBuilder mb ;
       mb = ab.DefineDynamicModule ( "emitmodule", "emitmodule.mod" ) ;

       TypeBuilder t = mb.DefineType ( "sample", TypeAttributes.Public ) ;

       MethodBuilder m = t.DefineMethod ( "fun", MethodAttributes.Public, typeof ( void ), null ) ;

       ILGenerator mil = m.GetILGenerator( ) ;

       Type[ ] tp = new Type [ 1 ] ;
       tp [ 0 ] = typeof ( String ) ;
       MethodInfo wm = typeof ( Console ).GetMethod ( "WriteLine", tp ) ;

       mil.Emit ( OpCodes.Ldstr, "Hello" ) ;
       mil.Emit ( OpCodes.Call, wm ) ;
       mil.Emit ( OpCodes.Ret ) ;

       t.CreateType( ) ;
       AssemblyBuilder asb = ( AssemblyBuilder ) t.Assembly ;
       asb.Save ( "emitassembly.dll" ) ; 
} 

The first step in creating a type is to create an assembly. We have created an assembly named ‘emitassembly’ using the Reflection.AssemblyName class. An object of AssemblyName class fully describes an assembly’s unique identity. Using this object we have obtained an object of the Reflection.Emit.AssemblyBuilder class. To obtain the assembly builder object we have called the DefineDynamicAssembly( ) method on current domain. The current domain is obtained by calling the GetDomain( ) method of the current thread. The parameters passed to the DefineDynamicAssembly( ) are the assembly name and an assembly access mode. The 'Save' mode specifies that the assembly we are creating will be persistable i.e will be saved on disk. If we specify the access mode as ‘Run’ instead of ‘Save’ the assembly would be transient. It can be executed but would not be saved on disk. The third mode is ‘RunAndSave’ which means the dynamic assembly can be executed and saved on disk. The type we would create will be written in a module built dynamically. We have created this module using the Reflection.Emit.ModuleBuilder object. The method DefineDynamicModule( ) creates a module named ‘emitmodule’ and saves it on disk in a file ‘emitmodule.mod’. We can now emit the type sample in the module emitmodule. The DefineType( ) method of the ModuleBuilder class defines the specified type and returns an object of Reflection.Emit.TypeBuilder object. The TypeBuilder class provides methods using which we can define classes, methods and fields.

In the next statement we have defined the method fun( ). The second parameter specifies the access specifier, whereas, third and fourth parameters specify the return type and an array containing types of parameters respectively.

Now since our type stands created, only thing remaining is to emit the body of the fun( ) method. The Reflection.Emit. ILGenerator class is used to generate IL instructions. The class contains a method called Emit( ) that is used to write the IL into the assembly.

We are supposed to call the WriteLine( ) method from the fun( ) method. So, we have firstly obtained the MethodInfo object representing the WriteLine( ) method. The GetMethod( ) method would match the WriteLine( ) method receiving a string.

mil.Emit ( OpCodes.Ldstr, "Hello" ) ;
mil.Emit ( OpCodes.Call, wm ) ;
mil.Emit ( OpCodes.Ret ) ; 

The first call to Emit( ) method would push the reference to the string “Hello” to the metadata. The second call would call the method as described by the second parameter. The third call to the Emit( ) method would return from the method. The OpCodes is the class that contains number of static fields representing the IL instructions.

Next, we have cooked the type by calling the CreateType( ) method of the TypeBuilder class. The Assembly property of the TypeBuilder class returns the dynamic assembly that contains calling type. We have stored this assembly object in the AssemblyBuilder class. This is possible because the Assembly class is the base class of the AssemblyBuilder class. Finally we have saved the dynamic assembly to the disk using the Save( ) method of the AssemblyBuilder class. Add the using statements as given below.

using System.Threading ;
using System.Reflection ;
using System.Reflection.Emit ; 

Let us use this assembly in a test program. Create another console application and write the following statements in Main( ).

sample s = new sample( ) ;
s.fun( ) ; 

Add reference to the ‘emitassembly.dll’ through Solution Explorer. Run the program. The string “Hello” would get displayed on the console.

Another way to invoke the fun( ) method is to use Reflection as shown below.

Assembly a = Assembly.LoadFrom ( "emitassembly.dll" ) ;
Type t = a.GetType ( "sample" ) ;
Object o = Activator.CreateInstance( t ) ;
t.InvokeMember ( "fun", BindingFlags.InvokeMethod, null, o, null ) ; 

Comments

Log in or create a user account to comment.

On Sale From April 2008

Let Us C
8th Ed.
C programming classic & best seller. 1 million+ copies sold!

Y. Kanetkar

On Sale From April 2008

Introduction to Object Oriented Programming & C++

Y. Kanetkar

On Sale From Fall 2008

Microsoft .NET Framework: Web Application Security

Vijay Mukhi

On Sale From Nolvember 2008

Quest C++ Courseware
12+ hours of instructional audio and animated slides.

Y. Kanetkar Asang Dani

On Sale From November 2008

A Programmer's Guide to Web Application Security

Vijay Mukhi

Latest Forum Posts