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

.NET Reflection.Emit 動態類生成實戰:從接口到實例

     編輯:Java 相關知識

動態生成類的應用場景

AOP 代理、O/R Mapping 實體類、動態適配器等場景常需運行時生成類型。.NET 通過 System.Reflection.Emit 命名空間提供底層 IL 發射能力,雖比 Java 字節碼操作繁瑣,但掌握核心流程後即可構建通用類型生成器。

核心類層級關係

生成鏈路:AppDomain → AssemblyBuilder → ModuleBuilder → TypeBuilder → MethodBuilder → ILGenerator。每一層都是下一層的容器,必須按順序構造。

通用 TypeCreator 實現

public class TypeCreator {
    private readonly Type _targetType; // 要實現的接口或繼承的基類

    public TypeCreator(Type targetType) => _targetType = targetType;

    public Type Build() {
        // 1. 獲取當前 AppDomain
        var domain = AppDomain.CurrentDomain;

        // 2. 定義動態組件
        var asmName = new AssemblyName { Name = "MyAssyFor_" + _targetType.Name };
        var asmBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);

        // 3. 定義動態模塊
        var modBuilder = asmBuilder.DefineDynamicModule("MyModFor_" + _targetType.Name);

        // 4. 定義新類型屬性
        string typeName = "Imp_" + _targetType.Name;
        var attrs = TypeAttributes.Class | TypeAttributes.Public;

        // 5. 區分接口實現 vs 類繼承
        Type parent = _targetType.IsInterface ? null : _targetType;
        Type[] interfaces = _targetType.IsInterface ? new[] { _targetType } : Type.EmptyTypes;

        // 6. 獲取 TypeBuilder
        var typeBuilder = modBuilder.DefineType(typeName, attrs, parent, interfaces);

        // 7. 為所有虛擬方法發射默認實現
        foreach (var m in _targetType.GetMethods()) {
            if (!m.IsVirtual) continue;

            var paramTypes = m.GetParameters().Select(p => p.ParameterType).ToArray();
            var methodBuilder = typeBuilder.DefineMethod(
                m.Name,
                MethodAttributes.Public | MethodAttributes.Virtual,
                m.ReturnType,
                paramTypes
            );

            // 8. IL 發射:Console.WriteLine("I'm {MethodName}ing")
            var il = methodBuilder.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "I'm " + m.Name + "ing");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
            il.Emit(OpCodes.Ret);
        }

        // 9. 創建並返回實際 Type
        return typeBuilder.CreateType();
    }
}

測試驗證

interface IAnimal { void Move(); void Eat(); }

var tc = new TypeCreator(typeof(IAnimal));
Type t = tc.Build();
IAnimal animal = (IAnimal)Activator.CreateInstance(t);
animal.Move(); // 輸出: I'm Moveing
animal.Eat();  // 輸出: I'm Eating

關鍵技術點解析

  • 僅能攔截虛擬方法:非虛擬/靜態方法無法通過繼承覆寫,Emit 生成的類同樣受限。
  • IL 發射基礎:Ldstr 加載字符串,Call 調用方法,Ret 返回。複雜邏輯需編寫更多 IL 指令。
  • AssemblyBuilderAccess.Run:僅內存運行,不持久化到磁盤;若需保存 DLL 可用 RunAndSave。
  • 泛型支持:TypeBuilder.DefineGenericParameters 可構建泛型類型,本文不展開。

優缺點對比

優勢劣勢
比 Remoting 透明代理效率高,無跨上下文調用開銷非虛擬方法無法攔截
可攔截 new 操作符(工廠模式返回動態類型)IL 手寫門檻高,維護成本大
適合 O/R Mapping 實體類生成、動態適配器調試困難(無源碼映射),需借助 IL 可視化工具

總結

Reflection.Emit 是 .NET 元編程的基石,掌握「AppDomain→Assembly→Module→Type→Method→IL」構造鏈路,即可構建通用動態類型生成器。實際項目中建議封裝高層 API(如表達式樹、Roslyn Source Generators)降低複雜度。

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