使用FieldBuilder创建一个字段,并在MethodBuilder ILCode Emit中添加一个字段值.<



我有一个方法,创建一个MethodBuilder方法,并定义使用ILGeneratorEmit + OpCodes的行为。

这个方法是在我之前的StackOverflow问题的帮助下创建的-感谢@Marc Gravell的帮助

行为是非常具体的,有一个原因,我必须使用MethodBuilder而不是c#中的标准方法定义创建一个方法,该方法计划用于在运行时修补逻辑的和谐后缀HarmonyMethod定义,我不想使用静态方法,因为我将做很多方法模拟,我不想有很多静态类和方法,所以我创建了以下类:

public class PostFixPatchFactory<T>
{
public T Value { get; set; }
public Exception Exception { get; set; }
public PostFixPatchFactory(T value)
=> Value = value;
public int TimesTriggered;
public FieldInfo field;
public MethodInfo GeneratePostfix()
{
string fieldName = $"DynamicField_{Guid.NewGuid()}";
AssemblyBuilder assembly = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"DynamicAssembly_{Guid.NewGuid()}"), AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder module = assembly.DefineDynamicModule($"DynamicModule_{Guid.NewGuid()}");
TypeBuilder typeBuilder = module.DefineType($"DynamicType_{Guid.NewGuid()}", TypeAttributes.Public);
FieldBuilder field = typeBuilder.DefineField(fieldName, typeof(T), FieldAttributes.Private | FieldAttributes.Static);

if (Value is Exception)
{
typeBuilder.DefineMethod("PostFix", MethodAttributes.Static | MethodAttributes.Public, typeof(void), null)
.GetILGenerator().ThrowException(typeof(T));
}
else
{
MethodBuilder method = typeBuilder.DefineMethod("PostFix", MethodAttributes.Static | MethodAttributes.Public,
typeof(void), new Type[] { typeof(T).MakeByRefType() });
var il = method.GetILGenerator();            
method.DefineParameter(1, ParameterAttributes.None, "__result");
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldsfld, field);
il.Emit(OpCodes.Stobj, typeof(T));
il.Emit(OpCodes.Ret);
}
var type = typeBuilder.CreateType();
type.GetField(fieldName, BindingFlags.NonPublic | BindingFlags.Static).SetValue(null, Value);
return type.GetMethod("PostFix", 
BindingFlags.Public | BindingFlags.Static);
}
public bool Prefix()
{
TimesTriggered++;
return false;
}
}

这个类的用法如下:

var harmony = new Harmony(nameof(Program));
HarmonyMethod prefix = new HarmonyMethod(typeof(Program).GetMethod(nameof(Prefix)));
var postFixPatchFactory = new PostFixPatchFactory<long>(6);

MethodInfo originalMethod = typeof(Program).GetMethod(nameof(TestMethodToChange));
MethodInfo scenarioToMockExample2 = typeof(ScenariosToMock).GetMethod("Example", BindingFlags.Static | BindingFlags.NonPublic);
HarmonyMethod scenarioToMockExample2PostFix = new HarmonyMethod(g.GeneratePostfix());
harmony.Patch(scenarioToMockExample2, prefix, scenarioToMockExample2PostFix);
var result = TestMethodToChange();
Console.WriteLine($"list result:[{result.Join(null,",")}]");

这工作得很好——除了它缺少一个功能,我希望——这是有产权的PostFixPatchFactory称为TimesExcecuted之类的品种,这样我可以跟踪方法多少次我修补excecuted——我努力实现这个特性——我想要这个功能的一部分IL发出新方法中的代码定义,我希望这个方法可以public实例字段或属性,可以使用如下:

int timesExcecuted = postFixPatchFactory.TimesExcecuted;
Console.WriteLine($"Method has been Triggered: {timesExcecuted}");

请帮助我-我不是很擅长IL或操作码,所以任何帮助都会非常感激

我试过使用一些新的FieldBuilder:

FieldBuilder prop = typeBuilder.DefineField($"DynamicProperty_{Guid.NewGuid()}", typeof(int), 
FieldAttributes.Public | FieldAttributes.Static);

并使用以下ILCode中的内容:

il.Emit(OpCodes.Ldsfld, prop);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);

但这不起作用,并返回一个无效代码异常

il.Emit(OpCodes.Ldsfld, prop);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);

你要离开"prop + 1"在堆栈上。您需要将其保存回

字段
il.Emit(OpCodes.Stsfld, prop);

我在。net 6中尝试了以下代码

AssemblyBuilder assembly =
AssemblyBuilder.DefineDynamicAssembly(new AssemblyName($"DynamicAssembly_{Guid.NewGuid()}"),
AssemblyBuilderAccess.RunAndCollect);
ModuleBuilder module = assembly.DefineDynamicModule($"DynamicModule_{Guid.NewGuid()}");
TypeBuilder typeBuilder = module.DefineType($"DynamicType_{Guid.NewGuid()}", TypeAttributes.Public);
FieldBuilder field =
typeBuilder.DefineField(fieldName, typeof(T), FieldAttributes.Private | FieldAttributes.Static);
FieldBuilder prop = typeBuilder.DefineField($"DynamicProperty_{Guid.NewGuid()}", typeof(int),
FieldAttributes.Public | FieldAttributes.Static);
MethodBuilder method = typeBuilder.DefineMethod("PostFix", MethodAttributes.Static | MethodAttributes.Public,
typeof(void), new Type[] { typeof(T).MakeByRefType() });
var il = method.GetILGenerator();
method.DefineParameter(1, ParameterAttributes.None, "__result");

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldsfld, field);
il.Emit(OpCodes.Stobj, typeof(T));
il.Emit(OpCodes.Ldsfld, prop);
il.Emit(OpCodes.Ldc_I4_1);
il.Emit(OpCodes.Add);
il.Emit(OpCodes.Stsfld, prop);
il.Emit(OpCodes.Ret);

var t = typeBuilder.CreateType();
var ot = Activator.CreateInstance(t);
var m = t.GetMethod("PostFix");


for (var i = 0; i < 5; i++)
m.Invoke(null, new Object[] { value });

var propVal = t.GetField(prop.Name).GetValue(null);
Debug.WriteLine($"propVal is {propVal}");

输出为

propVal is 5

相关内容

  • 没有找到相关文章

最新更新