Подтвердить что ты не робот

Внедрение среды выполнения GetMethod

В настоящее время я пытаюсь поменять реализацию свойства 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.

4b9b3361