上一篇介紹了 IL 的部分, 基礎的部分, 暫時就介紹到那里了, 接下來要進入代碼編寫階段了.
今天的主題是 在代碼運行的過程中, 去動態的創建類, 屬性, 方法.
來源:http://www.cnblogs.com/yingql/archive/2009/03/22/1419149.html
廢話不多說了, 直接上示例
一、示例
我這邊所用的示例跟來源中是一樣的,請看代碼:
public class Add { int numA = 0; public int NumA { get { return numA; } set { numA = value; } } int numB = 0; public int NumB { get { return NumB; } set { NumB = value; } } public Add(int a, int b) { numA = a; numB = b; } public int Calc() { return numA + numB; } }
我們要動態的創建這么一個類, 先不給你們看編碼過程, 先給你們看結果吧, 先知道下, 這么做, 能大致得到一個什么結果.
運行代碼之后, 會在bin里面得到一個 Elvin.dll 文件, 把這個文件和 ConsoleApplication2.exe 一起拿去反編譯, 去看里面 Add 類的內容
比較下來, 原生的和動態生成的稍有不同, 里面的IL代碼也會有部分不同,這個是正常的, 雖然是參照著反編譯的代碼寫的, 但是只是參照, 不是完全相同的.
二、編碼
先看幾個主要的部分, 后面我會把完整的代碼貼出來
1. 字段
private int numA; --> .field private int32 numA
var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private); //fieldABuilder.SetConstant(0); 此處為副初始值, 這里可省略
沒什么好解釋的, 一眼就能看懂, 至于這個 typeBldr 暫且不去管它
2. 屬性
//1.屬性 public int NumA { get{return numA;} set{numA = value;} } var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null); //2. 定義 get, set 方法
//2.1 get方法 代碼部分和上圖上的是有些不同的, 是參照著上圖這個來的 var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes); //ILGenerator var getAIL = getPropertyABuilder.GetILGenerator(); getAIL.Emit(OpCodes.Ldarg_0); //this getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA getAIL.Emit(OpCodes.Ret); //return numA
//2.2 set方法 代碼部分和上圖中是不一樣的, 是參照著上圖來的 var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) }); //ILGenerator var setAIL = setPropertyABuilder.GetILGenerator(); //setAIL.Emit(OpCodes.Nop); //這句可省略 setAIL.Emit(OpCodes.Ldarg_0); //this setAIL.Emit(OpCodes.Ldarg_1); //value setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value; setAIL.Emit(OpCodes.Ret); //return; //3.綁定get,set方法到屬性上 propertyABuilder.SetGetMethod(getPropertyABuilder); propertyABuilder.SetSetMethod(setPropertyABuilder);
很多時候, 我們用的是匿名的屬性, 如: public int NumA{get;set;}, 這種情況, 會自動生成一個匿名私有變量來代替numA, 去與之匹配, 屬性的本質是方法, 并不能用來存儲數據
3. 構造函數
IL代碼:
.method public hidebysig specialname rtspecialname instance void .ctor(int32 a, int32 b) cil managed { .maxstack 8 L_0000: ldarg.0 L_0001: ldc.i4.0 L_0002: stfld int32 ConsoleApplication2.Add::numA L_0007: ldarg.0 L_0008: ldc.i4.0 L_0009: stfld int32 ConsoleApplication2.Add::numB L_000e: ldarg.0 L_000f: call instance void [mscorlib]System.Object::.ctor() L_0014: nop L_0015: nop L_0016: ldarg.0 L_0017: ldarg.1 L_0018: stfld int32 ConsoleApplication2.Add::numA L_001d: ldarg.0 L_001e: ldarg.2 L_001f: stfld int32 ConsoleApplication2.Add::numB L_0024: nop L_0025: ret } //定義構造函數 ConstructorBuilder var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) }); var ctorIL = constructorBuilder.GetILGenerator(); // numA = a; ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Ldarg_1); ctorIL.Emit(OpCodes.Stfld, fieldABuilder); //NumB = b; ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Ldarg_2); ctorIL.Emit(OpCodes.Stfld, fieldBBuilder); ctorIL.Emit(OpCodes.Ret);
4. 方法
IL代碼:
.method public hidebysig instance int32 Calc() cil managed { .maxstack 2 .locals init ( [0] int32 num) L_0000: nop L_0001: ldarg.0 L_0002: ldfld int32 ConsoleApplication2.Add::numA L_0007: ldarg.0 L_0008: ldfld int32 ConsoleApplication2.Add::numB L_000d: add L_000e: stloc.0 L_000f: br.s L_0011 L_0011: ldloc.0 L_0012: ret } //8.定義方法 MethodBuilder var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes); var calcIL = calcMethodBuilder.GetILGenerator(); //加載私有字段numA calcIL.Emit(OpCodes.Ldarg_0); calcIL.Emit(OpCodes.Ldfld, fieldABuilder); //加載屬性NumB calcIL.Emit(OpCodes.Ldarg_0); calcIL.Emit(OpCodes.Ldfld, fieldBBuilder); //想加并返回棧頂的值 calcIL.Emit(OpCodes.Add); calcIL.Emit(OpCodes.Ret);
5. 到這里, 主要的部分就介紹完了, 下面給出檢驗的部分:
//9.結果 Type type = typeBldr.CreateType(); int a = 2; int b = 3; Object ob = Activator.CreateInstance(type, new object[] { a, b }); Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null));
執行之后, 會輸出 "The Result of 2 + 3 is 5"
至此, 今天要介紹的部分就結束了, 我把自己學習的過程和結果貼出來, 供有興趣的童鞋瞄一下.
以下是完整的代碼

static void Main(string[] args) { //1.構建程序集 var asmName = new AssemblyName("Elvinle"); var asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave); //2.創建模塊 var mdlBldr = asmBuilder.DefineDynamicModule("Elvin", "Elvin.dll"); //3.定義類, public class Add var typeBldr = mdlBldr.DefineType("Add", TypeAttributes.Public | TypeAttributes.BeforeFieldInit); //4. 定義屬性和字段 //4.1字段 FieldBuilder var fieldABuilder = typeBldr.DefineField("numA", typeof(Int32), FieldAttributes.Private); //fieldABuilder.SetConstant(0); 此處為副初始值, 這里可省略 var fieldBBuilder = typeBldr.DefineField("numB", typeof(Int32), FieldAttributes.Private); //4.2屬性 PropertyBuilder var propertyABuilder = typeBldr.DefineProperty("NumA", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null); var propertyBBuilder = typeBldr.DefineProperty("NumB", PropertyAttributes.None, CallingConventions.HasThis, typeof(Int32), null); //5.定義屬性numA的get;set;方法 MethodBuilder //5.1 get方法 var getPropertyABuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes); //ILGenerator GetPropertyIL(getPropertyABuilder, fieldABuilder); //var getAIL = getPropertyABuilder.GetILGenerator(); //getAIL.Emit(OpCodes.Ldarg_0); //this //getAIL.Emit(OpCodes.Ldfld, fieldABuilder); //numA //getAIL.Emit(OpCodes.Ret); //return numA //5.2 set方法 var setPropertyABuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) }); //ILGenerator SetPropertyIL(setPropertyABuilder, fieldABuilder); //var setAIL = setPropertyABuilder.GetILGenerator(); ////setAIL.Emit(OpCodes.Nop); //這句可省略 //setAIL.Emit(OpCodes.Ldarg_0); //this //setAIL.Emit(OpCodes.Ldarg_1); //value //setAIL.Emit(OpCodes.Stfld, fieldABuilder); //numA = value; //setAIL.Emit(OpCodes.Ret); //return; //5.3 綁定 propertyABuilder.SetGetMethod(getPropertyABuilder); propertyABuilder.SetSetMethod(setPropertyABuilder); //6.定義屬性numA的get;set;方法 MethodBuilder var getPropertyBBuilder = typeBldr.DefineMethod("get", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes); GetPropertyIL(getPropertyBBuilder, fieldBBuilder); var setPropertyBBuilder = typeBldr.DefineMethod("set", MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig, typeof(void), new Type[] { typeof(Int32) }); SetPropertyIL(setPropertyBBuilder, fieldBBuilder); propertyBBuilder.SetGetMethod(getPropertyBBuilder); propertyBBuilder.SetSetMethod(setPropertyBBuilder); //7.定義構造函數 ConstructorBuilder var constructorBuilder = typeBldr.DefineConstructor(MethodAttributes.Public | MethodAttributes.HideBySig, CallingConventions.HasThis, new Type[] { typeof(Int32), typeof(Int32) }); var ctorIL = constructorBuilder.GetILGenerator(); // numA = a; ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Ldarg_1); ctorIL.Emit(OpCodes.Stfld, fieldABuilder); //NumB = b; ctorIL.Emit(OpCodes.Ldarg_0); ctorIL.Emit(OpCodes.Ldarg_2); ctorIL.Emit(OpCodes.Stfld, fieldBBuilder); ctorIL.Emit(OpCodes.Ret); //8.定義方法 MethodBuilder var calcMethodBuilder = typeBldr.DefineMethod("Calc", MethodAttributes.Public | MethodAttributes.HideBySig, typeof(Int32), Type.EmptyTypes); var calcIL = calcMethodBuilder.GetILGenerator(); //加載私有字段numA calcIL.Emit(OpCodes.Ldarg_0); calcIL.Emit(OpCodes.Ldfld, fieldABuilder); //加載屬性NumB calcIL.Emit(OpCodes.Ldarg_0); calcIL.Emit(OpCodes.Ldfld, fieldBBuilder); //相加并返回棧頂的值 calcIL.Emit(OpCodes.Add); calcIL.Emit(OpCodes.Ret); //9.結果 Type type = typeBldr.CreateType(); int a = 2; int b = 3; Object ob = Activator.CreateInstance(type, new object[] { a, b }); Console.WriteLine("The Result of {0} + {1} is {2}", type.GetProperty("NumA").GetValue(ob), type.GetProperty("NumB").GetValue(ob), ob.GetType().GetMethod("Calc").Invoke(ob, null)); asmBuilder.Save("Elvin.dll"); Console.ReadKey(); } private static void GetPropertyIL(MethodBuilder getPropertyBuilder, FieldBuilder fieldBuilder) { //ILGenerator var getAIL = getPropertyBuilder.GetILGenerator(); getAIL.Emit(OpCodes.Ldarg_0); //this getAIL.Emit(OpCodes.Ldfld, fieldBuilder); //numA getAIL.Emit(OpCodes.Ret); //return numA } private static void SetPropertyIL(MethodBuilder setPropertyBuilder, FieldBuilder fieldBuilder) { //ILGenerator var setAIL = setPropertyBuilder.GetILGenerator(); //setAIL.Emit(OpCodes.Nop); //這句可省略 setAIL.Emit(OpCodes.Ldarg_0); //this setAIL.Emit(OpCodes.Ldarg_1); //value setAIL.Emit(OpCodes.Stfld, fieldBuilder); //numA = value; setAIL.Emit(OpCodes.Ret); //return; }
希望我在學習的過程中, 也能帶給你們一些不同的東西!
文章列表