首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

Emit 基礎教程:動態創建類別屬性、構造函數與方法

     編輯:關於.NET

System.Reflection.Emit 入門核心技能:為動態類型定義字段、屬性 (含 get/set)、構造函數、實例方法。本文以簡單的 Add 計算類為例,完整演示從 TypeBuilder 到 CreateType 的標準流程。

目標 C# 類別

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;
}

完整 Emit 實現步驟

1. 準備工作:程序集、模塊、類型

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);

2. 定義私有字段 (Backing Fields)

var fieldA = typeBuilder.DefineField("_a", typeof(int), FieldAttributes.Private);
var fieldB = typeBuilder.DefineField("_b", typeof(int), FieldAttributes.Private);
fieldA.SetConstant(0);
fieldB.SetConstant(0);

3. 定義屬性 A (含 get/set)

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 同理,略。

4. 定義構造函數

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);

5. 定義 Calc 方法

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);

6. 創建類型並測試

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實例方法/構造函數需指定

常見錯誤避坑

  1. 忘記 prop.SetGetMethod/SetSetMethod 導致屬性不可讀寫。
  2. 構造函數參數索引:Ldarg_0 是 this,Ldarg_1 為第一個參數。
  3. 字段未 SetConstant 導致預設值不生效 (僅限基本類型)。

掌握這套流程,即可動態生成任意 POCO 類型,為 ORM、序列化、動態代理打下基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved