usingSystem;usingSystem.Reflection;usingSystem.Reflection.Emit;classDemoAssemblyBuilder{publicstaticvoidMain(){// An assembly consists of one or more modules, each of which// contains zero or more types. This code creates a single-module// assembly, the most common case. The module contains one type,// named "MyDynamicType", that has a private field, a property // that gets and sets the private field, constructors that // initialize the private field, and a method that multiplies // a user-supplied number by the private field value and returns// the result. In C# the type might look like this:/*
public class MyDynamicType
{
private int m_number;
public MyDynamicType() : this(42) {}
public MyDynamicType(int initNumber)
{
m_number = initNumber;
}
public int Number
{
get { return m_number; }
set { m_number = value; }
}
public int MyMethod(int multiplier)
{
return m_number * multiplier;
}
}
*/AssemblyName aName =newAssemblyName("DynamicAssemblyExample");AssemblyBuilder ab =
AppDomain.CurrentDomain.DefineDynamicAssembly(
aName,
AssemblyBuilderAccess.RunAndSave);// For a single-module assembly, the module name is usually// the assembly name plus an extension.ModuleBuilder mb =
ab.DefineDynamicModule(aName.Name, aName.Name +".dll");TypeBuilder tb = mb.DefineType("MyDynamicType",
TypeAttributes.Public);// Add a private field of type int (Int32).FieldBuilder fbNumber = tb.DefineField("m_number",typeof(int),
FieldAttributes.Private);// Next, we make a simple sealed method.MethodBuilder mbMyMethod = tb.DefineMethod("MyMethod",
MethodAttributes.Public,typeof(int),new[]{typeof(int)});ILGenerator il = mbMyMethod.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);// Load this - always the first argument of any instance method
il.Emit(OpCodes.Ldfld, fbNumber);
il.Emit(OpCodes.Ldarg_1);// Load the integer argument
il.Emit(OpCodes.Mul);// Multiply the two numbers with no overflow checking
il.Emit(OpCodes.Ret);// Return// Next, we build the property. This involves building the property itself, as well as the// getter and setter methods.PropertyBuilder pbNumber = tb.DefineProperty("Number",// Name
PropertyAttributes.None,typeof(int),// Type of the propertynewType[0]);// Types of indices, if anyMethodBuilder mbSetNumber = tb.DefineMethod("set_Number",// Name - setters are set_Property by convention// Setter is a special method and we don't want it to appear to callers from C#
MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,typeof(void),// Setters don't return a valuenew[]{typeof(int)});// We have a single argument of type System.Int32// To generate the body of the method, we'll need an IL generator
il = mbSetNumber.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);// Load this
il.Emit(OpCodes.Ldarg_1);// Load the new value
il.Emit(OpCodes.Stfld, fbNumber);// Save the new value to this.m_number
il.Emit(OpCodes.Ret);// Return// Finally, link the method to the setter of our property
pbNumber.SetSetMethod(mbSetNumber);MethodBuilder mbGetNumber = tb.DefineMethod("get_Number",
MethodAttributes.PrivateScope | MethodAttributes.HideBySig | MethodAttributes.Public | MethodAttributes.SpecialName,typeof(int),newType[0]);
il = mbGetNumber.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);// Load this
il.Emit(OpCodes.Ldfld, fbNumber);// Load the value of this.m_number
il.Emit(OpCodes.Ret);// Return the value
pbNumber.SetGetMethod(mbGetNumber);// Finally, we add the two constructors.// Constructor needs to call the constructor of the parent class, or another constructor in the same classConstructorBuilder intConstructor = tb.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard | CallingConventions.HasThis,new[]{typeof(int)});
il = intConstructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);// this
il.Emit(OpCodes.Call,typeof(object).GetConstructor(newType[0]));// call parent's constructor
il.Emit(OpCodes.Ldarg_0);// this
il.Emit(OpCodes.Ldarg_1);// our int argument
il.Emit(OpCodes.Stfld, fbNumber);// store argument in this.m_number
il.Emit(OpCodes.Ret);var parameterlessConstructor = tb.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard | CallingConventions.HasThis,newType[0]);
il = parameterlessConstructor.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);// this
il.Emit(OpCodes.Ldc_I4_S,(byte)42);// load 42 as an integer constant
il.Emit(OpCodes.Call, intConstructor);// call this(42)
il.Emit(OpCodes.Ret);// And make sure the type is createdType ourType = tb.CreateType();// The types from the assembly can be used directly using reflection, or we can save the assembly to use as a referenceobject ourInstance = Activator.CreateInstance(ourType);
Console.WriteLine(ourType.GetProperty("Number").GetValue(ourInstance));// 42// Save the assembly for use elsewhere. This is very useful for debugging - you can use e.g. ILSpy to look at the equivalent IL/C# code.
ab.Save(@"DynamicAssemblyExample.dll");// Using newly created typevar myDynamicType = tb.CreateType();var myDynamicTypeInstance = Activator.CreateInstance(myDynamicType);
Console.WriteLine(myDynamicTypeInstance.GetType());// MyDynamicTypevar numberField = myDynamicType.GetField("m_number", BindingFlags.NonPublic | BindingFlags.Instance);
numberField.SetValue (myDynamicTypeInstance,10);
Console.WriteLine(numberField.GetValue(myDynamicTypeInstance));// 10}}