上一篇文章學習了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