AOP 代理、O/R Mapping 實體類、動態適配器等場景常需運行時生成類型。.NET 通過 System.Reflection.Emit 命名空間提供底層 IL 發射能力,雖比 Java 字節碼操作繁瑣,但掌握核心流程後即可構建通用類型生成器。
生成鏈路:AppDomain → AssemblyBuilder → ModuleBuilder → TypeBuilder → MethodBuilder → ILGenerator。每一層都是下一層的容器,必須按順序構造。
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
Ldstr 加載字符串,Call 調用方法,Ret 返回。複雜邏輯需編寫更多 IL 指令。TypeBuilder.DefineGenericParameters 可構建泛型類型,本文不展開。| 優勢 | 劣勢 |
|---|---|
| 比 Remoting 透明代理效率高,無跨上下文調用開銷 | 非虛擬方法無法攔截 |
| 可攔截 new 操作符(工廠模式返回動態類型) | IL 手寫門檻高,維護成本大 |
| 適合 O/R Mapping 實體類生成、動態適配器 | 調試困難(無源碼映射),需借助 IL 可視化工具 |
Reflection.Emit 是 .NET 元編程的基石,掌握「AppDomain→Assembly→Module→Type→Method→IL」構造鏈路,即可構建通用動態類型生成器。實際項目中建議封裝高層 API(如表達式樹、Roslyn Source Generators)降低複雜度。