System.Reflection.Emit 入門核心技能:為動態類型定義字段、屬性 (含 get/set)、構造函數、實例方法。本文以簡單的 Add 計算類為例,完整演示從 TypeBuilder 到 CreateType 的標準流程。
public class Add
{
private int _a = 0;
public int A { get => _a; set => _a = value; }
private int _b = 0;
public int B { get => _b; set => _b = value; }
public Add(int a, int b) { _a = a; _b = b; }
public int Calc() => _a + _b;
}
var asmName = new AssemblyName("DynamicMath");
var asmBuilder = AssemblyBuilder.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
var modBuilder = asmBuilder.DefineDynamicModule("DynamicMath", "DynamicMath.dll");
var typeBuilder = modBuilder.DefineType("Add", TypeAttributes.Public);
var fieldA = typeBuilder.DefineField("_a", typeof(int), FieldAttributes.Private);
var fieldB = typeBuilder.DefineField("_b", typeof(int), FieldAttributes.Private);
fieldA.SetConstant(0);
fieldB.SetConstant(0);
var propA = typeBuilder.DefineProperty("A", PropertyAttributes.None, typeof(int), null);
// get_A
var getA = typeBuilder.DefineMethod("get_A",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
typeof(int), Type.EmptyTypes);
var ilGetA = getA.GetILGenerator();
ilGetA.Emit(OpCodes.Ldarg_0); // this
ilGetA.Emit(OpCodes.Ldfld, fieldA); // this._a
ilGetA.Emit(OpCodes.Ret);
propA.SetGetMethod(getA);
// set_A
var setA = typeBuilder.DefineMethod("set_A",
MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
null, new[] { typeof(int) });
var ilSetA = setA.GetILGenerator();
ilSetA.Emit(OpCodes.Ldarg_0); // this
ilSetA.Emit(OpCodes.Ldarg_1); // value
ilSetA.Emit(OpCodes.Stfld, fieldA); // this._a = value
ilSetA.Emit(OpCodes.Ret);
propA.SetSetMethod(setA);
屬性 B 同理,略。
var ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public,
CallingConventions.HasThis,
new[] { typeof(int), typeof(int) });
var ilCtor = ctor.GetILGenerator();
// this._a = a
ilCtor.Emit(OpCodes.Ldarg_0); // this
ilCtor.Emit(OpCodes.Ldarg_1); // a
ilCtor.Emit(OpCodes.Stfld, fieldA);
// this._b = b
ilCtor.Emit(OpCodes.Ldarg_0); // this
ilCtor.Emit(OpCodes.Ldarg_2); // b
ilCtor.Emit(OpCodes.Stfld, fieldB);
ilCtor.Emit(OpCodes.Ret);
var calc = typeBuilder.DefineMethod("Calc",
MethodAttributes.Public,
typeof(int), Type.EmptyTypes);
var ilCalc = calc.GetILGenerator();
// return this._a + this._b
ilCalc.Emit(OpCodes.Ldarg_0);
ilCalc.Emit(OpCodes.Ldfld, fieldA);
ilCalc.Emit(OpCodes.Ldarg_0);
ilCalc.Emit(OpCodes.Ldfld, fieldB);
ilCalc.Emit(OpCodes.Add);
ilCalc.Emit(OpCodes.Ret);
var type = typeBuilder.CreateType();
asmBuilder.Save("DynamicMath.dll");
// 使用反射調用
var instance = Activator.CreateInstance(type, 10, 20);
var result = type.GetMethod("Calc").Invoke(instance, null);
Console.WriteLine(result); // 30
| 屬性 | 用途 |
|---|---|
MethodAttributes.SpecialName | 標記屬性存取器/運算符等特殊方法 |
MethodAttributes.HideBySig | 按簽名隱藏繼承成員 (C# 默認行為) |
CallingConventions.HasThis | 實例方法/構造函數需指定 |
prop.SetGetMethod/SetSetMethod 導致屬性不可讀寫。Ldarg_0 是 this,Ldarg_1 為第一個參數。SetConstant 導致預設值不生效 (僅限基本類型)。掌握這套流程,即可動態生成任意 POCO 類型,為 ORM、序列化、動態代理打下基礎。