C# Заменить тело метода лямбда-выражением - PullRequest
0 голосов
/ 12 апреля 2020

У меня есть функция для замены тела функции динамической c функцией. Функция для замены тела функции взята из следующих ответов SO [ Link 1 , Link 2 ].

Моя функция выглядит так:

public static class Helper
{
    public static unsafe void SetMethod(MethodInfo toReplace, MethodInfo toInject)
    {
        // Parameter validations...

        // Prepare methods
        RuntimeHelpers.PrepareMethod(toReplace.MethodHandle);
        RuntimeHelpers.PrepareMethod(toInject.MethodHandle);

        // For simplicity, we use only a nonvirtual method and a
        // pointer size of non 8
        if (toReplace.IsVirtual){ // Handle virtual method }
        else
        {
            if (IntPtr.Size == 4){ // Handle pointer size of 4 }
            {
                long* inj = (long*)b.MethodHandle.Value.ToPointer() + 1;
                long* tar = (long*)a.MethodHandle.Value.ToPointer() + 1;
#if DEBUG
                // Version x64 Debug
                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
                // Version x64 Release
                *tar = *inj;
#endif
            }
        }
    }
}

До сих пор работают следующие случаи:

public static class UnitTestsClass
{
    public static int GetTables(string somename)
    {
        return 12 + somename.Length;
    }
}

public static class ClassToInject
{
    public static int GetTables(string somename)
    {
        return 1;
    }
}

// Case: Replace with other function
public void Test1()
{
    var replaceFunc = typeof(UnitTestsClass).GetMethod("GetTables");
    var injectFunc = typeof(ClassToInject).GetMethod("GetTables");

    Helper.SetMethod(replaceFunc, injectFunc);
}

// Case: Replace with Func<>
public void Test2()
{
    var replaceFunc = typeof(UnitTestsClass).GetMethod("GetTables");
    Func<string, int> injectFunc = x => 2;

    Helper.SetMethod(replaceFunc, injectFunc.Method);
}

Но следующий случай с использованием лямбда-выражения isn ' пока не работает. SetMethod выдает ошибку

Запрошенная операция недопустима для DynamicMethod

в методе RuntimeHelpers.PrepareMethod. Если я закомментирую метод, я получаю ошибку

Запрошенная операция недопустима для DynamicMethod

снова, когда он пытается получить указатель на метод.

// Case: Replace with lambda expression
public void Test3()
{
    var replaceFunc = typeof(UnitTestsClass).GetMethod("GetTables");
    Expression<Func<string, int>> injectExpression = x => 2;
    Func<string, int> injectFunc = injectExpression.Compile();

    Helper.SetMethod(replaceFunc, injectFunc.Method);
}

Кто-нибудь может мне помочь заменить тело функции на функцию лямбда-выражения?

...