Here an example how we can create code at runtime. In this sample, I try to create the following class at runtime:
public class Person
{
private string _firstname;
private string _lastname;
public string FirstName
{
get { return _firstname; }
set { _firstname = value; }
}
public string LastName
{
get { return _lastname; }
set { _lastname = value; }
}
public Person()
{
_firstname = "";
_lastname = "";
}
public Person(string firstname, string lastname)
{
FirstName = firstname;
LastName = lastname;
}
public string GetFullName()
{
return FirstName + " " + LastName;
}
}
First of all, I'm going to implement the class as simple as posible, avoiding delegates an events. Here the result:
1.
// Our intermediate language generator
ILGenerator ilgen;
// The assembly builder
AssemblyBuilder asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("PeopleLibrary"), AssemblyBuilderAccess.RunAndSave);
// The module builder
ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule("PeopleLibrary", "PeopleLibrary.dll");
2.
// The person class builder
TypeBuilder personBuilder = modBuilder.DefineType("PeopleLibrary.Person", TypeAttributes.Class | TypeAttributes.Public);
// The default constructor
ConstructorBuilder ctorBuilder = personBuilder.DefineDefaultConstructor(MethodAttributes.Public);
3.
// Two fields: m_firstname, m_lastname
FieldBuilder fBuilderFirstName = personBuilder.DefineField("m_firstname", typeof(string), FieldAttributes.Private);
FieldBuilder fBuilderLastName = personBuilder.DefineField("m_lastname", typeof(string), FieldAttributes.Private);
// Two properties for this object: FirstName, LastName
PropertyBuilder pBuilderFirstName = personBuilder.DefineProperty("FirstName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null);
PropertyBuilder pBuilderLastName = personBuilder.DefineProperty("LastName", System.Reflection.PropertyAttributes.HasDefault, typeof(string), null);
4.
// Custom attributes for get, set accessors
MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
// get,set accessors for FirstName
MethodBuilder mGetFirstNameBuilder = personBuilder.DefineMethod("get_FirstName", getSetAttr, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetFirstNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, fBuilderFirstName); // returning the firstname field
ilgen.Emit(OpCodes.Ret);
MethodBuilder mSetFirstNameBuilder = personBuilder.DefineMethod("set_FirstName", getSetAttr, null, new Type[] { typeof(string) });
// Code generation
ilgen = mSetFirstNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Stfld, fBuilderFirstName); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ret);
5.
// get,set accessors for LastName
MethodBuilder mGetLastNameBuilder = personBuilder.DefineMethod("get_LastName", getSetAttr, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetLastNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldfld, fBuilderLastName); // returning the firstname field
ilgen.Emit(OpCodes.Ret);
MethodBuilder mSetLastNameBuilder = personBuilder.DefineMethod("set_LastName", getSetAttr, null, new Type[] { typeof(string) });
// Code generation
ilgen = mSetLastNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Stfld, fBuilderLastName); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ret);
6.
// Assigning get/set accessors
pBuilderFirstName.SetGetMethod(mGetFirstNameBuilder);
pBuilderFirstName.SetSetMethod(mSetFirstNameBuilder);
pBuilderLastName.SetGetMethod(mGetLastNameBuilder);
pBuilderLastName.SetSetMethod(mSetLastNameBuilder);
7.
// Now, a custom method named GetFullName that concatenates FirstName and LastName properties
MethodBuilder mGetFullNameBuilder = personBuilder.DefineMethod("GetFullName", MethodAttributes.Public, typeof(string), Type.EmptyTypes);
// Code generation
ilgen = mGetFullNameBuilder.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, mGetFirstNameBuilder); // getting the firstname
ilgen.Emit(OpCodes.Ldstr, " "); // an space
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, mGetLastNameBuilder); // getting the lastname
// We need the 'Concat' method from string type
MethodInfo concatMethod = typeof(String).GetMethod("Concat", new Type[] { typeof(string), typeof(string), typeof(string) });
ilgen.Emit(OpCodes.Call, concatMethod); // calling concat and returning the result
ilgen.Emit(OpCodes.Ret);
8.
// Another constructor that initializes firstname and lastname
ConstructorBuilder ctorBuilder2 = personBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new Type[] { typeof(string), typeof(string) });
ctorBuilder2.DefineParameter(1, ParameterAttributes.In, "firstname");
ctorBuilder2.DefineParameter(2, ParameterAttributes.In, "lastname");
// Code generation
ilgen = ctorBuilder2.GetILGenerator();
// First of all, we need to call the base constructor,
// the Object's constructor in this sample
Type objType = Type.GetType("System.Object");
ConstructorInfo objCtor = objType.GetConstructor(Type.EmptyTypes);
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Call, objCtor); // calling the Object's constructor
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_1);
ilgen.Emit(OpCodes.Call, mSetFirstNameBuilder); // setting the firstname field from the first argument (1)
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.Emit(OpCodes.Ldarg_2);
ilgen.Emit(OpCodes.Call, mSetLastNameBuilder); // setting the lastname field from the second argument (2)
ilgen.Emit(OpCodes.Ret);
9.
// Finally, create the type and save the assembly
personBuilder.CreateType();
asmBuilder.Save("PeopleLibrary.dll");
10. Using the library in another project that refereces
PeopleLibrary.dll:
Person p = new Person("oscar", "londono");
MessageBox.Show(p.GetFullName());
See
Part 2 and
Part 3.
5 comments:
Thank you very much, you did a magnificent work.
Keep on...
Eng. Sherif Mosad
Software Engineer
NextWare Inc., Egypt
The best example on System.Reflection.Emit that I've found on the net and exactly what I need!
Thank you very much for your great BLOG!
Greetings from Germany,
Daniel
Nice one as already stated the best on the net and believe me i searched a lot regarding this subject. Thanks a lot
Hi Oscar,
Your work was great! Now it resolve my problems in creating class..
But I still have question? how about setting a property of the field? Which I only want is a SET property.
Please help again.. kindly appreciate it.
Thank you very much! :D
Post a Comment