如何在PostFixPatchFactory中通过IL Emit实现补丁方法执行次数统计?
实现PostFix补丁执行次数统计方案
核心思路
给动态生成的补丁类型添加实例字段存储执行次数,在PostFix方法的IL开头插入自增逻辑,同时可通过接口封装属性方便外部访问。
步骤1:在动态类型中定义实例字段
在创建动态类型(TypeBuilder)的代码中,添加一个公开的int类型实例字段:
// 假设typeBuilder是你创建的动态类型构建器 var timesExecutedField = typeBuilder.DefineField( "TimesExecuted", typeof(int), FieldAttributes.Public | FieldAttributes.Instance);
步骤2:在PostFix方法IL中插入计数逻辑
在生成PostFix方法的ILGenerator代码最开头,添加字段自增的IL指令:
// 获取PostFix方法的IL生成器 var il = postFixMethodBuilder.GetILGenerator(); // 插入计数自增逻辑(必须放在原有业务逻辑之前) // 1. 加载当前实例(this)到栈顶 il.Emit(OpCodes.Ldarg_0); // 2. 取出当前TimesExecuted字段的值 il.Emit(OpCodes.Ldfld, timesExecutedField); // 3. 加载常数1 il.Emit(OpCodes.Ldc_I4_1); // 4. 执行加法(字段值 + 1) il.Emit(OpCodes.Add); // 5. 将计算结果存回TimesExecuted字段 il.Emit(OpCodes.Stfld, timesExecutedField); // 以下是你原来的PostFix方法IL逻辑(比如处理参数、调用原方法等) // ... 原有IL代码 ...
步骤3:通过接口简化访问(可选)
如果希望更优雅地访问计数,可定义一个接口并让动态类型实现它:
// 定义公共接口 public interface IPatchExecutionCounter { int TimesExecuted { get; } }
然后在动态类型构建时添加接口实现,并生成属性的get方法:
// 让动态类型实现接口 typeBuilder.AddInterfaceImplementation(typeof(IPatchExecutionCounter)); // 构建TimesExecuted属性 var propertyBuilder = typeBuilder.DefineProperty( "TimesExecuted", PropertyAttributes.None, typeof(int), null); // 生成属性的get方法 var getMethod = typeBuilder.DefineMethod( "get_TimesExecuted", MethodAttributes.Public | MethodAttributes.Virtual, typeof(int), Type.EmptyTypes); var getIl = getMethod.GetILGenerator(); getIl.Emit(OpCodes.Ldarg_0); getIl.Emit(OpCodes.Ldfld, timesExecutedField); getIl.Emit(OpCodes.Ret); // 绑定属性的get方法 propertyBuilder.SetGetMethod(getMethod);
之后创建补丁实例时,直接强转接口即可访问:
var patchInstance = Activator.CreateInstance(dynamicPatchType) as IPatchExecutionCounter; // 访问执行次数 Console.WriteLine($"补丁已执行:{patchInstance.TimesExecuted} 次");
关键注意事项
- 确保PostFix方法是实例方法:因为要访问实例字段,所以创建
MethodBuilder时不要加MethodAttributes.Static - 参数索引正确性:实例方法的第一个参数(
Ldarg_0)是当前实例,原有补丁的参数(如__instance、__result)会从Ldarg_1开始,需调整原有IL代码中的参数索引 - IL指令顺序:计数逻辑必须放在原有业务逻辑之前,确保每次执行都能正确累加
内容的提问来源于stack exchange,提问作者NannerBannaner23
相关产品推荐
相关产品推荐

