上一篇文章學習了IL的入門,接下來我們再通過兩個例子來了解下類的屬性、構造函數以及接口的使用
一、類的屬性、構造函數
1、先看下我們要構建的類的C#代碼,然後再進行IL的實現,示例代碼如下:
[Serializable] public class Dynamic { public int _a = 0; public const string ConstField = "const"; /// <summary> /// 定義屬性 /// </summary> public int A { get; set; } /// <summary> /// 構造函數 /// </summary> /// <param name="num"></param> public Dynamic(int num) { this.A = num; } public int Add(int num) { return this.A + num; } }View Code
2、通過以上代碼我們可以根據要求先定義字段_a、常量ConstField(在構造函數過程中未使用到,幫組了解類屬性的創建)以及給類加上序列化標簽,屬性可以通過TypeBuilder的DefineField創建,而序列化標簽需要通過TypeBuilder的CustomAttributeBuilder去創建,示例代碼如下:
//定義類可序列化 CustomAttributeBuilder serializable = new CustomAttributeBuilder(typeof(SerializableAttribute).GetConstructor(Type.EmptyTypes), new Type[] { }); typeBuilder.SetCustomAttribute(serializable); //定義常量 FieldBuilder fieldConst = typeBuilder.DefineField("ConstField", typeof(string), FieldAttributes.Static | FieldAttributes.Public | FieldAttributes.Literal); fieldConst.SetConstant("const"); //定義字段_a FieldBuilder aField = typeBuilder.DefineField("_a", typeof(int), FieldAttributes.Private); aField.SetConstant(0);View Code
3、通過TypeBuilder的DefineProperty定義屬性A,通過CustomAttributeBuilder給屬性添加對應的標簽,示例代碼如下:
//定義屬性A PropertyBuilder propertyABuilder = typeBuilder.DefineProperty("A", PropertyAttributes.None, typeof(int), null); CustomAttributeBuilder desAttributeBuilder = new CustomAttributeBuilder(typeof(DescriptionAttribute).GetConstructor(new Type[] { typeof(string) }), new object[] { "屬性A" }); propertyABuilder.SetCustomAttribute(desAttributeBuilder);//字段描述View Code
4、定義A屬性的get方法和set方法,get和set方法和普通的方法創建相同,用TypeBuilder的DefineMethod創建。示例代碼如下:
//定義屬性get方法 MethodBuilder methodABuilder = typeBuilder.DefineMethod("get", MethodAttributes.Public, typeof(Int32), Type.EmptyTypes); ILGenerator GetIL = methodABuilder.GetILGenerator(); GetIL.Emit(OpCodes.Ldarg_0); GetIL.Emit(OpCodes.Ldfld, aField); GetIL.Emit(OpCodes.Ret); propertyABuilder.SetGetMethod(methodABuilder); //定義屬性set方法 MethodBuilder methodBBuilder = typeBuilder.DefineMethod("set", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(Int32) }); ILGenerator SetIL = methodBBuilder.GetILGenerator(); SetIL.Emit(OpCodes.Ldarg_0); SetIL.Emit(OpCodes.Ldarg_1); SetIL.Emit(OpCodes.Stfld, aField); SetIL.Emit(OpCodes.Ret); propertyABuilder.SetSetMethod(methodBBuilder);View Code
5、構造函數的創建,構造函數是通過TypeBuilder的DefineConstructor去獲取,構造函數包含一個參數並賦值給_a,示例代碼如下:
//定義構造函數 ConstructorBuilder constructorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(Int32) }); ILGenerator constructorIL = constructorBuilder.GetILGenerator(); constructorIL.Emit(OpCodes.Ldarg_0); constructorIL.Emit(OpCodes.Ldarg_1); constructorIL.Emit(OpCodes.Stfld, aField); constructorIL.Emit(OpCodes.Ret);View Code
6、最後是定義方法。
//定義方法 MethodBuilder methodAddBuild = typeBuilder.DefineMethod("Add", MethodAttributes.Public, typeof(Int32), new Type[] { typeof(int) }); ILGenerator addIL = methodAddBuild.GetILGenerator(); addIL.Emit(OpCodes.Ldarg_0); addIL.Emit(OpCodes.Ldfld, aField); addIL.Emit(OpCodes.Ldarg_1); addIL.Emit(OpCodes.Add); addIL.Emit(OpCodes.Ret);View Code
到這一步一個動態類包含的屬性、構造函數以及方法就創建完成。可以借助reflector看下生成的結果。如下:
public int A { get; set; } 換成 public int A5 { get { return _a; } set { _a = value; } }
比較容易理解_a的存在
二、接口的實現
1、首先我們看下我們要實現一個什麼樣的接口,先看下構建類的C#代碼,示例代碼如下:
public class Mail : IMail { public string SendMail() { return "Send Success"; } } public interface IMail { string SendMail(); }View Code
2、實現接口,接口我們直接用IMail這個。就不用IL去創建了,首先我們創建一個typeBuilder,指定繼承接口IMail,可以用AddInterfaceImplementation來進行操作。示例代碼如下:
//定義類型 TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public); typeBuilder.AddInterfaceImplementation(typeof(IMail));View Code
3、實現接口。接口實現方法要怎麼定義在不清楚的情況下可以用reflector反編譯一個實現接口的方法來查看一下,觀察一下方法需要哪些MethodAttributes屬性。
通過以上信息可以定義接口實現的方法,接口實現就和之前例子定義的方法實現一樣。示例代碼如下:
MethodBuilder sendMailBuilder = typeBuilder.DefineMethod("SendMail", MethodAttributes.Public | MethodAttributes.ReuseSlot | MethodAttributes.Virtual | MethodAttributes.HideBySig, typeof(string), null); //定義接口 ILGenerator mailIL = sendMailBuilder.GetILGenerator(); LocalBuilder resultStr = mailIL.DeclareLocal(typeof(String)); mailIL.Emit(OpCodes.Nop); mailIL.Emit(OpCodes.Ldstr, "Send Success1"); mailIL.Emit(OpCodes.Stloc_0); mailIL.Emit(OpCodes.Ldloc_0); mailIL.Emit(OpCodes.Ret);View Code
實現後通過IL查看的代碼如下:
通過反編譯發現,接口實現是帶有override關鍵字的。而在定義實現方法時候如果不帶上virtual屬性又會提示接口未實現。也請知道的朋友解決下我的疑惑。
通過這篇文章我們了解到了動態類的創建,也了解到了接口的使用。從這兩個示例其實可以拓展出很多的東西比如繼承、屬性綁定自定義標簽、虛方法的重寫......這些東西也是需要不斷學習才能了解。在IL這塊的學習還有比較多的不懂在之後的學習再分享。
示例代碼下載:IL-3