我目前正在尝试通过用一些IL替换它来交换属性获取实现.我正在使用这个问题作为参考:如何替换指向从系统类继承的方法类中的方法的指针?
我唯一的区别是我的方法是通过MethodBuilder声明的:
MethodBuilder propertyGetBuilder = builder.DefineMethod
(
dynamicFunctionName,
MethodAttributes.Public,
propertyInfo.PropertyType,
Type.EmptyTypes
);
ILGenerator propertyGetIlGenerator = propertyGetBuilder.GetILGenerator();
propertyGetIlGenerator.Emit(OpCodes.Ldarg_0);
propertyGetIlGenerator.Emit(OpCodes.Ldstr, propertyInfo.Name);
propertyGetIlGenerator.Emit(OpCodes.Ldstr, relationKeyField.Name);
propertyGetIlGenerator.Emit(OpCodes.Ldstr, relationAttribute.RelationColumn);
propertyGetIlGenerator.Emit(OpCodes.Call, loadRelationMethod);
propertyGetIlGenerator.Emit(OpCodes.Ret);
Run Code Online (Sandbox Code Playgroud)
这会为生成的类型添加一个新函数 BeforeGet{PropertyName}
生成新类型后,我实例化它以确保内存地址存在:
dynamic fakeType = Activator.CreateInstance(type);
我从现有类中检索propertyInfo GetMethod,以及新创建的BeforeGet{PropertyName}fakeType类Type.
之后,在此函数中使用了两个MethodInfo:
RuntimeHelpers.PrepareMethod(methodA.MethodHandle);
RuntimeHelpers.PrepareMethod(methodB.MethodHandle);
unsafe
{
if (IntPtr.Size == 4)
{
int* inj = (int*)methodA.MethodHandle.Value.ToPointer() + 2;
int* tar = (int*)methodB.MethodHandle.Value.ToPointer() + 2;
#if DEBUG
Console.WriteLine("\nVersion x86 Debug?\n");
byte* injInst = (byte*)*inj;
byte* tarInst = (byte*)*tar;
int* injSrc = (int*)(injInst + 1);
int* tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
else
{
long* inj = (long*)methodA.MethodHandle.Value.ToPointer() + 1;
long* tar = (long*)methodB.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
Console.WriteLine("\nVersion x64 Debug\n");
byte* injInst = (byte*)*inj;
byte* tarInst = (byte*)*tar;
int* injSrc = (int*)(injInst + 1);
int* tarSrc = (int*)(tarInst + 1);
*tarSrc = (((int)injInst + 5) + *injSrc) - ((int)tarInst + 5);
#else
*tar = *inj;
#endif
}
}
Run Code Online (Sandbox Code Playgroud)
运行此代码之后,我在我的程序中执行以下代码:
LoadedTag.Item.ItemID;其中LoadedTag是应该获得ItemGetter 的新实现的类,但是我获得了空引用异常,因为该函数尚未被替换.
但是,如果我在立即窗口中执行此代码,则确实设置了ItemID并调用了拦截函数.
我认为问题是由于垃圾收集器删除了fakeType,它保存了在方法交换期间使用的函数的实际指针.如果是这样我该如何解决?
先感谢您!
如果需要请查询完整代码,我会将其上传到Github.
The*_*lis -1
从您的代码中尚不清楚,但是:“fakeType”与您交换指针的范围是否在同一范围内?
如果您更改了范围,并且 fakeType 确实不可用,则垃圾收集器可能会使内存空间无效。
因此,在生成 faketype 后,我会尝试立即移动“交换代码”以测试这是否是问题所在。
干杯,希望有帮助