В настоящее время я пытаюсь поменять реализацию свойства get, заменив ее небольшим количеством 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);
Это добавляет новую функцию к сгенерированному типу с именем BeforeGet{PropertyName}
После генерации нового типа я создаю его экземпляр, чтобы убедиться, что адрес памяти существует: dynamic fakeType = Activator.CreateInstance(type);
Я извлекаю propertyInfo GetMethod из существующего класса и недавно созданный класс Type класса FakeType BeforeGet{PropertyName}
.
После этого оба 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
}
}
После запуска этого кода я выполняю следующий код в моей Программе: LoadedTag.Item.ItemID;
Где LoadedTag - это класс, который должен был получить новую реализацию Item
Getter, но вместо этого я получил исключение нулевой ссылки, потому что функция не была заменена.
Однако, если я выполняю этот код в непосредственном окне, ItemID действительно установлен и вызывается функция перехвата.
Я думаю, что проблема связана с тем, что сборщик мусора удаляет fakeType, который содержит фактические указатели на функции, используемые во время замены метода. Если так, как я должен решить это?
Заранее спасибо!
При необходимости, пожалуйста, уточните полный код, и я отправлю его на Github.