Click here to Skip to main content
Click here to Skip to main content

Introduction to Creating Dynamic Types with Reflection.Emit: Part 2

, 1 May 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
Part 2 of an introduction to creating dynamic types. This article shows how to actually generate the methods in a dynamic type and how to call them.

Introduction

In my previous article, I introduced dynamic types, some possible uses for them, and then a high level walkthrough of how you might go about implementing a solution using dynamic types. That was all nice and fluffy, but now, let’s get down to an actual code example of implementing and calling dynamic types.

But first, for those that haven’t, or don’t want to read through the first article, here is a brief overview of what a dynamic type is.

Dynamic types are types, or classes, that are generated at runtime from within a program. When an application starts, you’ll have at least one AppDomain running. In order to add dynamic types to your AppDomain, you need to first create and add a dynamic assembly to your AppDomain. A dynamic assembly is an assembly that is created, and then added to an AppDomain at runtime. It is usually not saved to a file, but exists solely in memory. Once this is in place, and after a few more steps that I’ll cover, you can use the Reflection.Emit classes to create dynamic types.

So, what uses are dynamic types? First off, they are just plain cool (we are developers, we don’t need a better reason). I mean, come on? Emitting IL into memory at runtime to create your very own custom class! That’s just sweet. But seriously, the useful thing about dynamic types is that you can make your program evaluate the state of data that you may not know about until runtime in order to create a class that is optimized for the situation at hand.

The challenging part about dynamic types is that you can’t just dump C# code into your dynamic assembly and have the C# compiler compile it to IL. That would just be way too easy, and the Reflection.Emit team at Microsoft wanted you to have to work for your dynamic types. You have to use the classes in Reflection.Emit to define and generate type, method, constructor, and property definitions, and then insert or ‘emit’ IL opcodes into these definitions. Sound fun yet?

The problem statement

Every now and then, I run into a common problem when inheriting an application from another developer or dev team. The application uses DataSets to retrieve data from some database, but the developer used integer ordinals to pull data out of the DataRow, instead of string ordinals.

//Using integer ordinals:
foreach (DataRow row in dataTable.Rows)
{
    Customer c = new Customer();
    c.Address = row[0].ToString();
    c.City = row[1].ToString();
    c.CompanyName = row[2].ToString();
    c.ContactName = row[3].ToString();
    c.ContactTitle = row[4].ToString();
    c.Country = row[5].ToString();
    c.CustomerId = row[6].ToString();
    customers.Add(c);
}
//Using string ordinals:
foreach (DataRow row in dataTable.Rows)
{
    Customer c = new Customer();
    c.Address = row["Address"].ToString();
    c.City = row["City"].ToString();
    c.CompanyName = row["CompanyName"].ToString();
    c.ContactName = row["ContactName"].ToString();
    c.ContactTitle = row["ContactTitle"].ToString();
    c.Country = row["Country"].ToString();
    c.CustomerId = row["CustomerID"].ToString();
    customers.Add(c);
}

Any performance minded developer will quickly jump on this and state that using integer ordinals is faster than using string ordinals, and I completely agree with this. Just to demonstrate what the performance difference between the two are, I ran a quick performance measurement test using Nick Wienholt’s Performance Measurement Framework (*See note at the end of the article about the Performance Measurement Framework). The string ordinal test had a Normalized Test Duration (NTD from now on) of 4.87 compared to the integer ordinal test, meaning it took almost 3 times as long to execute than using integer ordinal. When building a performance critical application which has a high user load, that little bit of time difference might be unacceptable, especially when using integer ordinals can give you an easy performance improvement.

But, there is a maintenance problem with integer ordinals that has bitten me in the bum too many times. What happens if your DBA decides to redesign the table structure and adds a new column, not at the end of the table, but somewhere in the middle? What if the table was totally restructured with a whole new order to the columns? And, what if you, the developer, were not informed about this? Most likely, your app will crash because it is trying to cast a SQL data type into a non-matching .NET data type. Or even worse, your app doesn’t crash, but keeps chugging right along, but now with corrupt data.

Believe it or not, this happens every now and then (at least it has to me). Applications are more susceptible these days due to the increasing use of web services maintained either by a third party vendor or another development team. This situation recently prompted me to write a utility class that would give me the speed of integer ordinals, but with the maintainability of string ordinals.

Version 1 of the DataRowAdapter

To solve this simple problem, I came up with the following class:

public class DataRowAdapter
{
    private static bool isInitialized = false;
    private static int[] rows = null;             
    public static void Initialize(DataSet ds)
    {
        if (isInitialized) return;
        rows = new int[ds.Tables[0].Columns.Count];
        rows[0] = ds.Tables[0].Columns["Address"].Ordinal;
        rows[1] = ds.Tables[0].Columns["City"].Ordinal;
        rows[2] = ds.Tables[0].Columns["CompanyName"].Ordinal;
        rows[3] = ds.Tables[0].Columns["ContactName"].Ordinal;
        .
        .//pull the rest of the ordinal values by column name
        .
        isInitialized = true;
    }
    //static properties for returning integer ordinal 
    public static int Address { get {return rows[0];} }
    public static int City { get {return rows[1];} }
    public static int CompanyName { get {return rows[2];} }
    public static int ContactName { get {return rows[3];} } 
}

The purpose of this class is fairly evident. You pass in the DataSet into the static Initialize() method; this goes through each column in the DataTable and stores off the integer ordinal into an integer array. Then, I have a static property defined to pass back the integer ordinal for that column. Shown below is the code that uses this class to retrieve data from a DataRow.

DataRowAdapter.Initialize(dataSet);

foreach (DataRow row in dataSet.Tables[0].Rows)
{
    Customer c = new Customer();
    c.Address = row[DataRowAdapter.Address].ToString();
    c.City = row[DataRowAdapter.City].ToString();
    c.CompanyName = row[DataRowAdapter.CompanyName].ToString();
    c.ContactName = row[DataRowAdapter.ContactName].ToString();
    .
    .
    customers.Add(c);
}

This is all fairly straightforward. The DataRowAdapter acts as an integer ordinal retrieval tool, so now, your code can pull from a DataRow in a pseudo-string ordinal way, but behind the scenes, it’s still accessing based on the integer index of the column. And, if your DBA ever decides to change around the order of the columns, you won’t have to update your data access code.

To see if the DataRowAdapter actually helped with performance, I ran a performance test comparing this method to using a straight integer ordinal. Accessing data from a DataRow with the DataRowAdapter came up with an NTD of 1.04, just 4% slower. Not bad compared to using string ordinals, which was almost 300% slower!

A better way to solve this problem

This works great, lasts long time. But, as I started using this class design for more and more DataTables, I realized that it was getting to be a pain to maintain. I had to create a new class with hard coded static properties for each DataTable column signature. After about 15 different classes, it starts to get on one’s nerves.

Enter the Reflection.Emit namespace. The Reflection.Emit namespace has a bunch of classes whose primary job is to dynamically create assemblies and types at runtime, meaning while the application is running. Why is this important? Because with Reflection.Emit, you can now dynamically generate a DataRowAdapter class per DataTable at runtime, instead of hard coding a bunch of very specialized static classes. In theory, you should just pass in a DataSet or DataTable into a factory class, and the factory class should generate a new DataRowAdapter class based on the column structure of the DataTable. And, once the factory has generated a new DataRowAdapter, it won’t have to generate it again because it’ll be already loaded into the AppDomain. Pretty handy, eh?

The down side of using Reflection.Emit (there’s always a downside, right?) is that you can’t just stuff a string variable full of C# code and then compile it on the fly (actually with the System.CodeDom namespace and the CSharpCodeProvider class, you could do this, but this would have to run through the C# compiler and then the JIT compiler, which would be a lot slower). With Reflection.Emit, you create a new assembly in memory and then emit IL opcodes directly into the assembly. The up side is you don’t have to run through the C# compiler because the code you are emitting is IL. The down side is you have to understand IL. But, there are ways to make that easier, which I’ll cover in a bit.

Defining a generic interface

There is another problem with Reflection.Emit. You don’t have an API to program against. Think about it, the class that you are going to generate at runtime doesn’t exist at design time. So, how do you call it? Ahh, the power of interfaces.

So, the first step is to figure out what the public interface for the dynamic type will be. This is a fairly simple example, so the interface should also be fairly simple. So, after pondering long and hard about this, I came up with the following interface:

public interface IDataRowAdapter
{
    int GetOrdinal(string colName);
}

Since I don’t know the column names that will be needed, the interface can’t very well have hard coded static properties, can it? Instead, I decided on a single method called GetOrdinal() that takes a string value of the column name and returns the integer ordinal for that column.

All dynamic types generated by the factory class will inherit from this interface, and this interface will also be the return type for the factory class. Your program will call the factory class, passing in a DataTable, and get an IDataRowAdapter in return. It can then call IDataRowAdapter.GetOrdinal() to get the integer ordinal for a column name.

There is another way to go about this. Instead of defining a common interface that all dynamic types can inherit from, you could use late binding and access the dynamic type’s methods and properties via Reflection. But, this should be considered “bad form” for several reasons. First, the interface is a contract with the type. It guarantees that the method will exist and it can be called. If you use late bound method calls via Reflection, there is no guarantee that the method exists for that type. You could misspell the method name, and the compiler wouldn’t give you a warning. You wouldn’t know there was a problem until the application was running and tried to invoke the method, at which point a Reflection exception would be thrown.

The second problem with late bound method calls is that Reflection is just plain slow. Any performance benefit that you gained by using dynamic types would most likely be lost because of doing so.

Which way do I go?

When prototyping the new DataRowAdapter with the interface IDataRowAdapter in C#, I tried several different methods to determine what the integer ordinal value is from a string column name. Because I’m trying to find a fast, dynamic way to get data from a DataRow, I created a performance test for each method and measured the results. The following is a list of the different methods and their results compared against using an integer ordinal.

  1. Use a switch statement based on the string column name passed in.
  2. Create an enumeration for the column values, and use a switch block on the enumeration (thought it would be faster than switching on a string). Use Enum.Parse(columnName) to create the instance of the enum.
  3. Use multiple “if” blocks to check the column name.
  4. Use a Dictionary<string, int> to store the column name / ordinal mapping.

The results were a bit surprising. The slowest was switching on an enumeration. This was because Enum.Parse() uses Reflection to create an instance of the column enumeration. This method had an NTD of 10.74 compared to the integer ordinal.

The next slowest was the string switch statement, coming in with an NTD of 3.71 compared to the integer ordinal. Not all that much faster than using a straight string ordinal.

Next was using the generic Dictionary with an NTD of 3.4 compared to the integer ordinal. Still, not that great.

And, the winner was multiple “if” statements, with an NTD of 2.6 compared to the integer ordinal. Now, it's still a far amount slower than a straight integer ordinal lookup, but it's much faster than a string lookup, and you still get the column name safety.

The actual implementation that I’ve decided to go with is shown below in C#. This is what I’ll base the IL off of when I use Reflection.Emit to generate the type.

public class DataRowAdapter : IDataRowAdapter
{
    public int GetOrdinal(string colName)
    {
        if (colName == "Address")
                    return 0;
        if (colName == "City")
                    return 1;
        if (colName == "CompanyName")
                    return 2;
        if (colName == "ContactName")
                    return 3;
        .
        .
        throw new ApplicationException("Column not found");
    }
}

Now, can you see the benefit to dynamic types? You would never hard code something like this at design time, because you don’t know for sure that the City column is really at ordinal position 1. But with Reflection.Emit, you do know because you generate the class based on the evidence determined at runtime.

The solution design

The next thing to do is come up with a design for the class that will generate the dynamic types and return them to the caller. For the dynamic type generator, I decided that I’d go with the Factory pattern. This fits the needs of this solution perfectly since the caller can’t explicitly call the constructor of the dynamic type. Also, I want to hide the implementation details of the dynamic type away from the caller. So, the public API for the Factory class will be this:

public class DataRowAdapterFactory
{
    public static IDataRowAdapter CreateDataRowAdapter(DataSet ds, string tableName)
    {
        //method implementation
    }
    public static IDataRowAdapter CreateDataRowAdapter(DataTable dt)
    {
        //method implementation
    }
    //private factory methods
}

Because each dynamic type will be hard coded for a specific list of columns, each DataTable passed into the factory with a different TableName value will cause the factory to generate a new type. If a DataTable is passed into the Factory a second time, the dynamic type for that DataTable has already been generated and the Factory will only have to return an instance of the already generated type.

Setting up a dynamic type

(Note, some of the Reflection.Emit function descriptions may be repeated from my last article, but I wanted the reader to be able to follow along even if they haven’t read Part 1.)

Before getting down to writing the functionality of the GetOrdinal() method, I wanted to cover how to set up an assembly to hold the new type. Since Reflection.Emit cannot add a new type to an existing assembly, you have to generate a brand new one in memory. To do this, you use the AssemblyBuilder class.

private static AssemblyBuilder asmBuilder = null;
private static ModuleBuilder modBuilder = null;
private static void GenerateAssemblyAndModule()
{
    if (asmBuilder == null)
    {
        AssemblyName assemblyName = new AssemblyName();
        assemblyName.Name = "DynamicDataRowAdapter";
        AppDomain thisDomain = Thread.GetDomain();
        asmBuilder = thisDomain.DefineDynamicAssembly(
                     assemblyName, AssemblyBuilderAccess.Run);
        modBuilder = assBuilder.DefineDynamicModule(
                     asmBuilder.GetName().Name, false);
    }
}

To create a new AssemblyBuilder instance, you need to start out with an AssemblyName instance. Create a new instance, and assign it the name you want to call your assembly. Then, get the AppDomain for the static Thread.GetDomain() method. This AppDomain instance will allow you to create the new dynamic assembly with the DefineDynamicAssembly() method. Just pass in the AssemblyName class and an enumeration value for AssemblyBuilderAccess. In this instance, I don’t want to save this assembly to file, but if I did, I could use AssemblyBuilderAccess.Save or AssemblyBuilderAccess.RunAndSave.

Luckily, once an AssemblyBuilder has been created, the same instance can be used over and over to create all the new dynamic types, so it only needs to be created once.

Once the AssemblyBuilder has been created, a ModuleBuilder instance also needs to be created, which will be used later to create a new dynamic type. Use the AssemblyBuilder.DefineDynamicModule() method to create a new instance. If you want, you could create as many modules for your dynamic assembly as you want to, but for this case, only one is needed.

Now, on to creating the dynamic type:

private static TypeBuilder CreateType(ModuleBuilder modBuilder, string typeName)
{
    TypeBuilder typeBuilder = modBuilder.DefineType(typeName, 
                TypeAttributes.Public | 
                TypeAttributes.Class |
                TypeAttributes.AutoClass | 
                TypeAttributes.AnsiClass | 
                TypeAttributes.BeforeFieldInit | 
                TypeAttributes.AutoLayout, 
                typeof(object), 
                new Type[] {typeof(IDataRowAdapter)});
    return typeBuilder;
}

A dynamic type is created via the TypeBuilder class. You create an instance of a TypeBuilder class by calling the ModuleBuilder.DefineType() method, passing in the class name for the first argument, and for the second argument, an enumeration value of TypeAttributes that defines all the characteristics of your dynamic type. The third argument is a Type instance of the class that your dynamic type inherits from; in this case, System.Object. And, the fourth value is an array of interfaces that the dynamic type will inherit from. This is very important in this solution, so I pass in a value of IDataRowAdapter.

One thing to point out here. Have you noticed a pattern in how you create instances of these Reflection.Emit classes? AppDomain is used to create AssemblyBuilder, AssemblyBuilder is used to create ModuleBuilder, ModuleBuilder is used to create TypeBuilder? This is another example of a Factory pattern, which is a common theme throughout the Reflection.Emit namespace. Can you guess how you would create a MethodBuilder, ConstructorBuilder, FieldBuilder, or a PropertyBuilder class? Through the TypeBuilder, of course!

Design changes that arise because of using dynamic types

I want to stop for a minute and talk about my design. The final prototype of the DataRowAdapter uses the string column name to determine which ordinal to return via multiple if statements. But now that the type is created at runtime, there is a faster way available. Comparing two integers is much faster than comparing two strings. So, how can you get an integer value from a string? Why string.GetHashCode(), of course! Now, before you start screaming that a hash code is not guaranteed to be unique for every possible string out there, let me explain. While I can’t say that every string will output a unique hash code value, I can say that there is a large possibility that it will be unique within a small list of strings, like a list of column names for a DataTable.

So, I created a method to check and see if all the hash codes for a DataTable are unique. If it finds that the column names are unique, then the dynamic type factory will output a switch statement to check for integer values. If it finds that they are not unique, then the dynamic type factory will output multiple if statements that check for string equality.

I wanted to see how much of a difference using the column name’s hash code was to using a string comparison in order to justify the added complexity of the type factory. When I ran a performance test, I found that using the hash code gave me an NTD of 1.35 compared to a straight integer ordinal usage. Now granted, the original static DataRowAdapter had an NTD of 1.04, but I also had to maintain one class per DataTable, which if an application is quite large, can become very cumbersome. With the dynamic type used in this solution, there is no maintenance. And, very often, a maintenance benefit will trump a performance benefit, especially if the performance degradation isn’t too bad.

Next, I ran a test to check how fast the DataRowAdapter would run if I were using string comparisons. These results here weren’t all that great. I came up with an NTD of 1.9, twice as slow as using straight integer ordinals, but still decently faster than using straight string ordinals. But, I wanted to keep this in the design because of the off chance that the hash code values for a list of column names are not unique.

So, with this design, the majority of the time you’ll get the performance benefit of integer equality checks, and every now and then, the type will fall back onto string equality checks. Either way, both are faster than using straight string ordinals.

Writing the GetOrdinal method with Reflection.Emit

Next is the heart of the dynamic type factory, creating the GetOrdinal() method. Up to now, I haven’t shown much work with IL, but now, we’re going to get down and dirty with Reflection.Emit.

Below is the code for GetOrdinal:

private static void CreateGetOrdinal(TypeBuilder typeBuilder, DataTable dt)
{
    int colIndex = 0;
    //create the needed type arrays
    Type[] oneStringArg =  new Type[1] {typeof(string)};
    Type[] twoStringArg = new Type[2] {typeof(string), typeof(string)};
    Type[] threeStringArg =  
       new Type[3] {typeof(string), typeof(string), typeof(string)};
    //create needed method and contructor info objects
    ConstructorInfo appExceptionCtor = 
       typeof(ApplicationException).GetConstructor(oneStringArg);
    MethodInfo getHashCode  = typeof(string).GetMethod("GetHashCode");
    MethodInfo stringConcat = typeof(string).GetMethod("Concat", threeStringArg);        
    MethodInfo stringEquals = typeof(string).GetMethod("op_Equality", twoStringArg);
    //defind the method builder
    MethodBuilder method = typeBuilder.DefineMethod("GetOrdinal", 
       MethodAttributes.Public | MethodAttributes.HideBySig | 
       MethodAttributes.NewSlot | MethodAttributes.Virtual | 
       MethodAttributes.Final, typeof(Int32), oneStringArg);              
    //create IL Generator
    ILGenerator il = method.GetILGenerator();
    //define return jump label
    System.Reflection.Emit.Label outLabel = il.DefineLabel();
    //define return jump table used for the many if statements
    System.Reflection.Emit.Label[] jumpTable = 
                new System.Reflection.Emit.Label[dt.Columns.Count];
    if (AllUniqueHashValues(dt))
    {
        //create the return int index value, and hash value
        LocalBuilder colRetIndex = il.DeclareLocal(typeof(Int32));
        LocalBuilder parmHashValue = il.DeclareLocal(typeof(Int32));
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Callvirt, getHashCode);
        il.Emit(OpCodes.Stloc_1);
        foreach (DataColumn col in dt.Columns)
        {
            //define label
            jumpTable[colIndex] = il.DefineLabel();
            //compare the two hash codes
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Ldc_I4, col.ColumnName.GetHashCode());
            il.Emit(OpCodes.Bne_Un, jumpTable[colIndex]);
            //if equal, load the ordianal into loc0 and return
            il.Emit(OpCodes.Ldc_I4, col.Ordinal);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Br, outLabel);
            il.MarkLabel(jumpTable[colIndex]);

            colIndex++;
        }
    }
    else
    {
        //create the return int index value, and hash value
        LocalBuilder colRetIndex = il.DeclareLocal(typeof(Int32));     
        foreach (DataColumn col in dt.Columns)
        {
            //define label
            jumpTable[colIndex] = il.DefineLabel();
            //compare the two strings
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldstr, col.ColumnName);
            il.Emit(OpCodes.Call, stringEquals);
            il.Emit(OpCodes.Brfalse, jumpTable[colIndex]);
            //if equal, load the ordianal into loc0 and return
            il.Emit(OpCodes.Ldc_I4, col.Ordinal);
            il.Emit(OpCodes.Stloc_0);
            il.Emit(OpCodes.Br, outLabel);
            il.MarkLabel(jumpTable[colIndex]);

            colIndex++;
        }
    }
          
    //error handler if cant find column name
    il.Emit(OpCodes.Ldstr, "Column '");
    il.Emit(OpCodes.Ldarg_1);
    il.Emit(OpCodes.Ldstr, "' not found");
    il.Emit(OpCodes.Callvirt, stringConcat);
    il.Emit(OpCodes.Newobj, appExceptionCtor);
    il.Emit(OpCodes.Throw);
    //label for if user found column name
    il.MarkLabel(outLabel);
    //return ordinal for column
    il.Emit(OpCodes.Ldloc_0);
    il.Emit(OpCodes.Ret);
}

The first thing we have to do is set up a few items so they are ready to be used later on in the method. The GetOrdinal() method we’re going to emit will need to call four methods during its lifetime. They are String.GetHashCode(), String.Concat(), String.op_Equality(), and the constructor for ApplicationException. We’ll need to create MethodInfo and ConstructorInfo objects in order to emit the “call” or “callvirt” opcodes for these methods.

The next step is to create a MethodBuilder instance from the TypeBuilder. Again, I just looked at the prototype I wrote in C# in ILDASM to figure out what MethodAttributes to use when defining my MethodBuilder. The TypeBuilder.DefineMethod() is very similar to DefineConstructor (described in the first article) except for one thing. DefineMethod() has one more argument for you to define the return type. If the method you are defining doesn’t have a return value, then just pass in null for this argument.

Next, an ILGenerator instance is needed, which is created almost exactly the same as with the MethodBuilder.

Now, I need to define several Labels. A Label is used in Reflection.Emit to tell the CLR where to jump or branch off to. Branching is how if statements, switch statements, and loops are written in IL, and are very similar to goto statements. The first label I define will be used when the correct ordinal has been found and the process should jump to the end of the method so it can return. Then a Label array is created, one Label for each column name, which will be used for defining either the block of “if” statements for string comparisons or for the “switch” statement for comparing the column name’s hash value.

In order to use a label, you must first define it with ILGenerator.DefineLabel(). Next, you pass it into the ILGenerator.Emit() method as the second argument, where the first argument is any one of the many branch opcodes (Brfalse, Brtrue, Be, Bge, Ble, Br, etc). This basically says “if x is (true, false, ==, >=, <=) then go to this label”. Finally, you must use the ILGenerator.MarkLabel() method, passing in the Label instance as the only argument. What this does is tell the process to jump to where the Label is marked when it hits the branch opcodes. For “if” statements, you will mark your Label below where your branch opcode is defined. For “loop” statements, you’ll most likely mark your Label above where your branch opcode is defined (hence, the loop).

So, how do I know what IL to emit for GetOrdinal? Same way I knew how to define the MethodBuilder. Code it up in C#, compile it, and take a look at the generated IL in ILDasm.exe. Once you have the IL from ILDASM, it’s just a simple, but tedious task of duplicating the IL with ILGenerator.Emit(Opcodes.*) statements.

I’m not going to go over every line of code in GetOrdinal(), since it should be fairly obvious if you look at the IL generated for the C# version of GetOrdinal().

Creating and using an instance of the dynamic type

Now that all the tools are in place to create a dynamic type, I’ve got one last area to cover: how the Factory class creates a new dynamic type and returns a new instance to the caller, and how the dynamic type can be used. Shown below is the basic structure of the Factory class.

public static IDataRowAdapter CreateDataRowAdapter(DataTable dt)
{
    return CreateDataRowAdapter(dt, true);
}

TypeBuilder typeBuilder = null;

private static IDataRowAdapter CreateDataRowAdapter(DataTable dt, 
                               bool returnAdapter)
{
    //return no adapter if no columns or no table name
    if (dt.Columns.Count == 0 || dt.TableName.Length == 0)
                return null;
    //check to see if type instance is already created
    if (adapters.ContainsKey(dt.TableName))
                return (IDataRowAdapter)adapters[dt.TableName];
    //Create assembly and module 
    GenerateAssemblyAndModule();
    //create new type for table name
    TypeBuilder typeBuilder = CreateType(modBuilder, "DataRowAdapter_" + 
                              dt.TableName.Replace(" ", ""));
    //create get ordinal
    CreateGetOrdinal(typeBuilder, dt);
    IDataRowAdapter dra = null;
          
    Type draType = typeBuilder.CreateType();
    //assBuilder.Save(assBuilder.GetName().Name + ".dll");
    //Create an instance of the DataRowAdapter
    IDataRowAdapter dra = (IDataRowAdapter) = 
                    Activator.CreateInstance(draType, true);
    //cache adapter instance
    adapters.Add(dt.TableName, dra);
    //if just initializing adapter, dont return instance
    if (!returnAdapter)
                return null;
    return dra;
}

The first thing the Factory does is check if the TypeBuilder class has been created yet. If it hasn’t, the factory calls the private methods I’ve already shown that creates the DynamicAssembly, DynamicModule, TypeBuilder, and the GetOrdinal() method for the dynamic type. Once these steps are complete, it uses the TypeBuilder.CreateType() method to return a Type instance for the DataRowAdapter. I then use Activator.CreateInstance using the generated type to actually create a working instance of the dynamic type. Yeah!

This is the moment of truth. Creating a new type and calling the constructor on the type will invoke the constructor that was built earlier. If any of the IL was emitted wrong, the CLR will throw an exception. If everything is fine, you’ll have a working copy of the DataRowAdapter. After the Factory has an instance of the DataRowAdapter, it will cast it down and return an IDataRowAdapter.

Using a dynamic type is pretty simple. The main thing to remember is that you have to code against an interface, because at design time, the class doesn’t exist. Shown below is an example code that calls the DataRowAdapterFactory class and asks for a DataRowAdapter. The Factory returns an IDataRowAdapter instance, and you can then call GetOrdinal() and pass in the desired column name. The DataRowAdapter will figure out what integer ordinal is being requested and return it. This is shown below.

IDataRowAdapter dra = DataRowAdapterFactory.CreateDataRowAdapter(dataTable);
foreach (DataRow row in data.Rows)
{
    Customer c = new Customer();
    c.Address = row[dra.GetOrdinal("Address")].ToString();
    c.City = row[dra.GetOrdinal("City")].ToString();
    c.CompanyName = row[dra.GetOrdinal("CompanyName")].ToString();
    c.ContactName = row[dra.GetOrdinal("ContactName")].ToString();
    .
    .//pull the rest of the values
    customers.Add(c);
}

Below are the class and sequence diagrams that illustrate how the Factory is used to create an IDataRowAdapter, and how the IDataRowAdapter is then used by the consumer.

Dynamic Types Class Diagram

Dynamic Types Sequence Diagram

How do I know that my IL is correct?

(This section is a bit of a repeat from my first article, but I included it for instructional purposes.)

OK, so now, I’ve completed the dynamic type factory, I compile the solution in Visual Studio, and there are no errors. If I run it, it’ll work, right? Maybe. The downside of Reflection.Emit is that you can emit just about any combination of IL that you want. But, there is no design time compiler checking to see if what you wrote is valid IL. Sometimes, when you “bake” your type with TypeBuilder.CreateType(), it’ll throw an exception if there is something wrong, but only for certain problems. Sometimes, you won’t get an error until you actually try to call a method for the first time. Remember the JIT compiler? The JIT compiler won’t try to compile and verify your IL until the first time a method is called. So, it’s very much possible, and actually probable, that you won’t find out that your IL is invalid until you are actually running your application, the type has been generated, and you are calling the dynamic type for the first time. But, the CLR gives helpful error messages, right? Not likely. Usually, I get the ever helpful “Common Language Runtime detected an invalid program” exception.

OK, so how do you tell if your dynamic type contains valid IL? PEVerify.exe to the rescue! PEVerify is a tool that comes with .NET that can inspect an assembly for valid IL code, structure, and metadata. But, in order to use PEVerify, you must save the dynamic assembly to a physical file (remember, up until now, the dynamic assembly only exists in memory). To create an actual file for the dynamic assembly, you’ll need to make a few changes to the Factory code. First, change the last argument in the AppDomain.DefineDynamicAssembly() method from AssemblyBuilderAccess.Run to AssemblyBuilderAccess.RunAndSave. Second, change AssemblyBuilder.DefineDynamicModule() to pass in the assembly file name as its second argument. And finally, a new line of code to save off the assembly to file. I put it just after I call TypeBuilder.CreateType(), as shown below:

Type draType = typeBuilder.CreateType();
assBuilder.Save(assBuilder.GetName().Name + ".dll");

Now that that is in place, run the application and create the dynamic type. Once it has run, you should have a new DLL named “DynamicDataRowAdapter.dll” in the Debug folder for your solution (assuming you are using a Debug build). Open the .NET command prompt window and type “PEVerify <path to the assembly>\ DynamicDataRowAdapter.dll”, and hit Enter. PEVerify will validate the assembly, and either tell you everything is fine, or tell you what is wrong. The nice thing about PEVerify is that it gives decently detailed information about what is wrong and where to find the problem. Also note that just because PEVerify comes up with an error doesn’t mean that the assembly won’t run. For example, when I first wrote the Factory class, I used the “callvirt” opcode when I called the static String.Equals() method. This caused PEVerify to output an error, but it still ran. This was an easy fix to call the static method with the “call” opcodes instead, and the next time I ran PEVerify, it found no errors.

(static and sealed method calls are called with the “call” opcode instead of the “callvirt” opcode. This is because the “callvirt” opcode causes the CLR to check the inheritance chain of a type to figure out what function to actually call. Since static and sealed methods aren’t affected by inheritance, the CLR doesn’t have to do this check and can call the method directly with the “call” opcode.)

One last thing, if you change your code to output a physical file, be sure to change it back to the way it was before. This is because once a dynamic assembly has been saved to file, it is locked down, so you won’t be able to add any new dynamic types after the first one has been generated and saved to file. This would be a problem in this situation because every time a new DataTable is passed into the factory, it will try to create a new dynamic type. But after the first type has been generated, if you save off the assembly to file, an exception will be thrown.

Another way to double check your IL is to use the free tool Reflector (just Google it) to decompile the IL back into C# and take a look at what you emitted.

Talk about over-engineering!

So, this seems like a heck of a lot of complicated work for a little bit of a performance gain. Is it really worth it? Maybe not…probably not. It depends on the application you are writing. Some applications that I’ve written are server apps that are very heavily hit and need every little bit of performance gain it can get.

The point of this article wasn’t to show off a brand new utility class, but to give you a taste of what you can accomplish with Reflection.Emit. There are so many possibilities. For instance, the next article I hope to write in this series will cover a simple Aspect Oriented Programming (AOP) framework totally done with dynamic types and Reflection.Emit.

Debugging dynamic types

There is one dark side to dynamic types. They can be hard to maintain and debug. And, here lies a problem that I like to bring up in development. I call it the “Hit by a Bus” problem. IL is fairly complex. Not a lot of people out there know it or even want to know it. So, what happens if you are the only one on your dev team that knows anything about IL and you get hit by a bus? Who will maintain the solution? I’m not saying that you should forgo the benefits of dynamic types if they are warranted, but it’s always good to have at least two people who understand the complexities in a product.

The second problem is debugging. Since you are dumping IL code into memory, it’s not all that easy to just create a break point in Visual Studio and step through your IL if you ever have to debug your dynamic type. There are alternatives and solutions, and I’ll be talking about them in a future article on dynamic types.

Performance note about integer ordinals

In this article, I ran comparison performance measurements against accessing a DataRow with both string and integer ordinals. Just because an integer ordinal is four times faster than a string ordinal, doesn’t mean your web page will load four times as fast. Not even close! Pulling data out of a DataReader is just one small item a page might do. This is especially true if your page uses any kind of data binding. Data binding is very expensive, and its performance cost will most likely make your integer ordinal gain unnoticeable. So, don’t expect to see a visible performance gain on a one time page load. The only way you might see some benefit is if you put your web page under a load testing tool and measured the requests per second when being hit with a high number of concurrent users.

Performance Measurement Framework note

All performance tests referenced in this article were done using Nick Wienholt’s Performance Measurement Framework. You can download the source code and an article describing how to use it, from here. All test results were calculated by executing the problem code block 5,000 times, with a time measurement taken for this duration. This is then repeated 10 times, giving 10 time measurements. These 10 measurements are then calculated together, giving various statistics, such as normalized value, median, mean, min and max, and standard deviation. The performance measurement framework does all this for you. You just write the problem code block and a bit of the framework plug-in setup, and then run the test.

Other options to Reflection.Emit

There are several other options to using Reflection.Emit. You could always build up a System.CodeDom object graph that represents the code you want to generate, and run it through a CodeDomProvider to create an assembly in memory, and then load the assembly into your AppDomain. Alternatively, you could also use the CodeDom classes to dump a string of C# code into a CodeSnippetExpression, and then run it through a CodeDomProvider. Both of these would work for you, but the whole point of creating dynamic types is for efficiencies. Both of these methods have to run through the C# compiler, and then the assembly has to be loaded into your AppDomain before they can be called by your application. These are extra steps that you can skip when creating dynamic types via Reflection.Emit.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

jconwell

United States United States
I have been a professional developer since 1996. My experience comes from many different industries; Data Mining Software, Consulting, E-Commerce, Wholesale Operations, Clinical Software, Insurance, Energy.
 
I started programming in the military, trying to find better ways to analyze database data, eventually automating my entire job. Later, in college, I automated my way out of another job. This gave me the great idea to switch majors to the only thing that seemed natural…Programming!
Follow on   Twitter

Comments and Discussions

 
GeneralNeat, Here is a similar Concept [modified] Pinmembercodezilla942-Oct-07 14:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.141022.2 | Last Updated 1 May 2006
Article Copyright 2006 by jconwell
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid