Click here to Skip to main content
12,820,108 members (22,514 online)
Click here to Skip to main content
Articles » Languages » C# » Reflection » Downloads


71 bookmarked
Posted 1 May 2006

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

, 1 May 2006 CPOL
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.
using System;
using System.Windows.Forms;
using System.Threading;
using System.Data;
using System.Diagnostics;
using System.Reflection;
using System.Reflection.Emit;
using System.Collections.Generic;

namespace EmitPerfTesting
	/// <summary>
	/// Summary description for DataRowAdapterFactory.
	/// </summary>
	public class DataRowAdapterFactory
		private static AssemblyBuilder assBuilder = null;
		private static ModuleBuilder modBuilder = null;
		private static Dictionary<string, IDataRowAdapter> adapters = new Dictionary<string, IDataRowAdapter>();

		public static IDataRowAdapter CreateDataRowAdapter(DataSet ds, string tableName)
			IDataRowAdapter dra = null;

			if (ds.Tables.Count > 0)
				foreach (DataTable dt in ds.Tables)
					if (dt.TableName == tableName)
						dra = CreateDataRowAdapter(dt, true);
						CreateDataRowAdapter(dt, false);

			return dra;

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

		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 is already created
			if (adapters.ContainsKey(dt.TableName))
				return (IDataRowAdapter)adapters[dt.TableName];

			//Create assembly and module 

			//create new type for table name
			TypeBuilder typeBuilder = CreateType(modBuilder, "DataRowAdapter_" + dt.TableName.Replace(" ", ""));			

			//create get ordinal
			CreateGetOrdinal(typeBuilder, dt);

			Debug.WriteLine("Creating instance of adapter for table " + dt.TableName);
			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;

		private static void GenerateAssemblyAndModule()
			if (assBuilder == null)
				Debug.WriteLine("Creating AssemblyBuilder for DynamicDataRowAdapter assembly");
				AssemblyName draAssemblyName = new AssemblyName();
				draAssemblyName.Name = "DynamicDataRowAdapter";
				AppDomain thisDomain = Thread.GetDomain();
				//TODO:figure out parm list to use for isSynchronized parm = true;
				assBuilder = thisDomain.DefineDynamicAssembly(draAssemblyName, AssemblyBuilderAccess.Run);
				//assBuilder = thisDomain.DefineDynamicAssembly(draAssemblyName, AssemblyBuilderAccess.RunAndSave);

				Debug.WriteLine("Creating Module for DynamicDataRowAdapter assembly");
				modBuilder = assBuilder.DefineDynamicModule(assBuilder.GetName().Name, false);
				//modBuilder = assBuilder.	(assBuilder.GetName().Name, assBuilder.GetName().Name + ".dll", false);					

		private static TypeBuilder CreateType(ModuleBuilder modBuilder, string typeName)
			Debug.WriteLine("Creating type for table " + typeName);

			TypeBuilder typeBuilder = modBuilder.DefineType(typeName,
				TypeAttributes.Public |
				TypeAttributes.Class |
				TypeAttributes.AutoClass |
				TypeAttributes.AnsiClass |
				TypeAttributes.BeforeFieldInit |
				new Type[] { typeof(IDataRowAdapter) });

			return typeBuilder;

		private static void CreateGetOrdinal(TypeBuilder typeBuilder, DataTable dt)
			Debug.WriteLine("Creating method for GetOrdinal() with hash checks");
			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(
				MethodAttributes.Public | 
				MethodAttributes.HideBySig | 
				MethodAttributes.NewSlot | 
				MethodAttributes.Virtual | 
				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.Callvirt, getHashCode);

				foreach (DataColumn col in dt.Columns)
					//define label
					jumpTable[colIndex] = il.DefineLabel();

					//compare the two hash codes
					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.Br, outLabel);

				//create the return int index value, and hash value
				LocalBuilder colRetIndex = il.DeclareLocal(typeof(Int32));

				foreach (DataColumn col in dt.Columns)
					Debug.WriteLine("Creating accessor for column " + col.ColumnName + " at ordinal " + col.Ordinal.ToString());

					//define false label
					jumpTable[colIndex] = il.DefineLabel();

					//compare the two strings
					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.Br, outLabel);


			//error handler if cant find column name						
			il.Emit(OpCodes.Ldstr, "Column '");
			il.Emit(OpCodes.Ldstr, "' not found");
			il.Emit(OpCodes.Callvirt, stringConcat);
			il.Emit(OpCodes.Newobj, appExceptionCtor);

			//label for if user found column name

			//return ordinal for column

		private static bool AllUniqueHashValues(DataTable dt)
			Dictionary<int, int> uniqueHashes = new Dictionary<int, int>(dt.Columns.Count);
			foreach (DataColumn col in dt.Columns)
				int hash = col.ColumnName.GetHashCode();
				if (!uniqueHashes.ContainsKey(hash))
					uniqueHashes.Add(hash, hash);
					return false;				
			return true;				

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


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


About the Author

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!

You may also be interested in...

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170308.1 | Last Updated 1 May 2006
Article Copyright 2006 by jconwell
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid