Создать слабый делегат динамического метода (объект ссылки, объект [] обр)

Исходный код:https://www.pastefile.com/4mzhyg

Я пытаюсь создать делегат формата:

    public delegate TReturn MethodCallerR<TTarget, TReturn>(ref TTarget target, object[] args);

 /// <summary>
    /// Generates a strongly-typed open-instance delegate to invoke the specified method
    /// </summary>
    public static MethodCallerR<TTarget, TReturn> DelegateForCallR<TTarget, TReturn>(this MethodInfo method) {

        int key = GetKey<TTarget, TReturn>(method, kMethodCallerName);
        Delegate result;
        if (cache.TryGetValue(key, out result))
            return (MethodCallerR<TTarget, TReturn>)result;

        return GenDelegateForMember<MethodCallerR<TTarget, TReturn>, MethodInfo>(
                method, key, kMethodCallerName, GenMethodInvocationR<TTarget>,
                typeof(TReturn), typeof(TTarget).MakeByRefType(), typeof(object[]));
    }

функция слабого типа:

    public static MethodCallerR<object, object> DelegateForCallR(this MethodInfo method) {
        return DelegateForCallR<object, object>(method);
    }

делегировать создателя:

   static TDelegate GenDelegateForMember<TDelegate, TMember>(TMember member, int key, string dynMethodName,
            Action<TMember> generator, Type returnType, params Type[] paramTypes)
    where TMember : MemberInfo
    where TDelegate : class {
        var dynMethod = new DynamicMethod(dynMethodName, returnType, paramTypes, true);

        emit.il = dynMethod.GetILGenerator();
        generator(member);

        var result = dynMethod.CreateDelegate(typeof(TDelegate));
        cache[key] = result;
        return (TDelegate)(object)result;
    }

и генератор кода IL:

 static void GenMethodInvocationR<TTarget>(MethodInfo method) {



        var weaklyTyped = typeof(TTarget) == typeof(object);



        // push arguments in order to call method
        var prams = method.GetParameters();
        var imax = prams.Length;
        for (int i = 0; i < imax; i++) {

            emit.ldarg1()        // stack<= paramsValuesArray[] //push array
            .ldc_i4(i)        // stack<= index push(index)
            .ldelem_ref();    // stack[top]<=paramsValuesArray[i]

            var param = prams[i];
            var dataType = param.ParameterType;

            if (dataType.IsByRef)
                dataType = dataType.GetElementType();

            emit.unbox_any(dataType);

            emit.declocal(dataType);

            emit.stloc(i);

        }



        if (!method.IsStatic)
        {
            var targetType = weaklyTyped ? method.DeclaringType : typeof(TTarget);
            emit.ldarg0();  //stack[top]=target;
            emit.ldind_ref();//stack[top]=ref target;
            if (weaklyTyped)
                emit.unbox_any(targetType); //stack[top]=(TargetType)target;
        }


        //load parms from local 'list' to evaluation 'steak'
        for (int i = 0; i < imax; i++) {
            var param = prams[i];

            emit.ifbyref_ldloca_else_ldloc(i, param.ParameterType);
        }

        // perform the correct call (pushes the result)
        emit.callorvirt(method);


        //check of ref and out params and
        for (int i = 0; i < prams.Length; i++) {

            var paramType = prams[i].ParameterType;
            if (paramType.IsByRef)
            {
                var byRefType = paramType.GetElementType();
                emit.ldarg1() // stack<= paramsValuesArray[]
                .ldc_i4(i) // stack<= i //push(index)
                .ldloc(i); // stack<= list[i] //push local list element at 'i' on steak
                if (byRefType.IsValueType)
                    emit.box(byRefType);   // if ex. stack[top] =(object)stack[top]
                emit.stelem_ref(); //  // paramsValuesArray[i]= pop(stack[top]);
            }
        }

        if (method.ReturnType == typeof(void))
            emit.ldnull();
        else if (weaklyTyped)
            emit.ifvaluetype_box(method.ReturnType);

        emit.ret();


    }

Примером структуры, которую я использую, является Vector3 с методом Set:

  public struct Vector3{
    public float x;
    public float y;
    public float z;

    public Vector3(float x,float y,float z){
        this.x=x;
        this.y=y;
        this.z=z;
    }

    public void Set(float x,float y,float z){
        this.x=x;
        this.y=y;
        this.z=z;
    }
}

поэтому я делаю:

   object vector3Obj=new Vector3(4,5,6);
    MethodInfo method=typeof(Vector3).GetMethod("Set");
      MethodCallerR<object,object> m = methodInfo.DelegateForCallR();
             m(ref vector3Obj,new object[]{1f,2f,3f});
    Console.Write(vector3.x);

Никогда не добирайтесь до исполняемого делегата, но когда он вызывает Delegate.CreateDelegate, он взрывается:

см. строку: dynMethod.CreateDelegate (typeof (TDelegate));

с ошибкой:

InvalidProgramException: Invalid IL code in (wrapper dynamic-method) object:MC<> (object&,object[]): IL_004f: call 0x00000009 refereeing that actual IL code has error at emit.call(method), but when I use helper function:

    FastReflection.GenDebugAssembly<object>("my.dll",null,null,methodInfo,vector3Obj.GetType(),new Type[]{typeof(float),typeof(float),typeof(float)});

который сгенерирует my.dll и откроется с помощью ILSpy. Я вижу, что метод из того же кода IL сгенерирован очень хорошо.

    public static object MethodCallerR(ref object ptr, object[] array)
{
    float num = (float)array[0];
    float num2 = (float)array[1];
    float num3 = (float)array[2];
    ((Vector3)ptr).Set(num, num2, num3);
    return null;
}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
51
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение. Во-первых, хотя сгенерированный метод был правильным, ссылка на настройку не передавалась. Поэтому я попытался сгенерировать другой метод.

public static object MethodCallerR(ref object ptr, object[] array)
{
    float num = (float)array[0];
    float num2 = (float)array[1];
    float num3 = (float)array[2];
    Vector3 vector = (Vector3)ptr;
    vector.Set(num, num2, num3);
    ptr = vector;
    return null;
}

Поэтому я изменил код IL на:

      static void GenMethodInvocationR<TTarget>(MethodInfo method) {





        //this version winxalex generates more optimized code
        //Generated
        //            public static object MethodCallerR(ref object ptr, object[] array)
        //            {
        //                float num = (float)array[0];
        //                float num2 = (float)array[1];
        //                float num3 = (float)array[2];
        //                Vector3 vector = (Vector3)ptr;
        //                vector.Set(num, num2, num3);
        //                ptr = vector;
        //                return null;
        //            }
        //
        var weaklyTyped = typeof(TTarget) == typeof(object);
        var targetType = weaklyTyped ? method.DeclaringType : typeof(TTarget);
        var isNotStatic = !method.IsStatic;
        LocalBuilder targetLocal = null;

        // push arguments in order to call method
        var prams = method.GetParameters();
        var imax = prams.Length;
        for (int i = 0; i < imax; i++) {

            emit.ldarg1()        // stack<= paramsValuesArray[] //push array
            .ldc_i4(i)        // stack<= index push(index)
            .ldelem_ref();    // stack[top]<=paramsValuesArray[i]

            var param = prams[i];
            var dataType = param.ParameterType;

            if (dataType.IsByRef)
                dataType = dataType.GetElementType();

            emit.unbox_any(dataType);

            emit.declocal(dataType);

            emit.stloc(i);

        }



        if (isNotStatic)
        {

            emit.ldarg0();  //stack[top]=target;
            emit.ldind_ref();//stack[top]=ref target;
            if (weaklyTyped)
                emit.unbox_any(targetType); //stack[top]=(TargetType)target;

            targetLocal = emit.declocal(targetType); //TargetType tmpTarget; list[0]=tmpTarget;

            emit.stloc(targetLocal)     //list[0]=stack.pop();
            .ifclass_ldloc_else_ldloca(targetLocal, targetType);
        }


        //load parms from local 'list' to evaluation 'steak'
        for (int i = 0; i < imax; i++) {
            var param = prams[i];

            emit.ifbyref_ldloca_else_ldloc(i, param.ParameterType);
        }

        // perform the correct call (pushes the result)
        emit.callorvirt(method);


        if (isNotStatic && targetType.IsValueType) {
            emit.ldarg0().ldloc(targetLocal).box(targetType).stind_ref();
        }


        //check of ref and out params and
        for (int i = 0; i < prams.Length; i++) {

            var paramType = prams[i].ParameterType;
            if (paramType.IsByRef)
            {
                var byRefType = paramType.GetElementType();
                emit.ldarg1() // stack<= paramsValuesArray[]
                .ldc_i4(i) // stack<= i //push(index)
                .ldloc(i); // stack<= list[i] //push local list element at 'i' on steak

                if (byRefType.IsValueType)
                    emit.box(byRefType);   // if ex. stack[top] =(object)stack[top]
                emit.stelem_ref(); //  // paramsValuesArray[i]= pop(stack[top]);
            }
        }

        if (method.ReturnType == typeof(void))
            emit.ldnull();
        else if (weaklyTyped)
            emit.ifvaluetype_box(method.ReturnType);

        emit.ret();



        //vexe orignial modified by winxalex to use reference of object (ref obj) and to return value to reference

        //GENERATES
        //            public static object MethodCallerR(ref object ptr, object[] array)
        //            {
        //                Vector3 vector = (Vector3)ptr;
        //                float num = (float)array[0];
        //                float arg_56_1 = num;
        //                float num2 = (float)array[1];
        //                float arg_56_2 = num2;
        //                float num3 = (float)array[2];
        //                vector.Set(arg_56_1, arg_56_2, num3);
        //                ptr = vector;
        //                return null;
        //            }


        //            var weaklyTyped = typeof(TTarget) == typeof(object);
        //            var targetType = weaklyTyped ? method.DeclaringType : typeof(TTarget);
        //            // push target if not static (instance-method. in that case first arg is always 'this')
        //            if (!method.IsStatic)
        //            {
        //
        //                emit.declocal(targetType); //TargetType tmpTarget; list[0]=tmpTarget;
        //                emit.ldarg0();  //stack[0]=target;
        //                emit.ldind_ref();//stack[top]=ref target;
        //                if (weaklyTyped)
        //                    emit.unbox_any(targetType); //stack[0]=(TargetType)target;
        //                emit.stloc0()     //list[0]=stack.pop();
        //                .ifclass_ldloc_else_ldloca(0, targetType);
        //                // if (type.IsValueType) stack[0]=list[0].address, else stack[0]=list[0];
        //                // if (type.IsValueType) emit.ldloca(idx); else emit.ldloc(idx); return this;
        //            }
        //
        //            // if method wasn't static that means we declared a temp local to load the target
        //            // that means our local variables index for the arguments start from 1
        //            int localVarStart = method.IsStatic ? 0 : 1;
        //
        //            // push arguments in order to call method
        //            var prams = method.GetParameters();
        //            for (int i = 0, imax = prams.Length; i < imax; i++) {
        //                emit.ldarg1()        // stack<= paramsValuesArray //push array
        //                .ldc_i4(i)        // stack<= index push index
        //                .ldelem_ref();    // pop array, index and push array[index]
        //
        //                var param = prams[i];
        //                var dataType = param.ParameterType;
        //
        //                if (dataType.IsByRef)
        //                    dataType = dataType.GetElementType();
        //
        //                var tmp = emit.declocal(dataType);
        //                emit.unbox_any(dataType)
        //                .stloc(tmp)
        //                .ifbyref_ldloca_else_ldloc(tmp, param.ParameterType);
        //
        ////v2
        //
        //
        ////                emit.unbox_any(dataType);
        ////
        ////                emit.declocal(dataType);
        ////                emit.stloc(i+localVarStart)
        ////                .ifbyref_ldloca_else_ldloc(i+localVarStart, param.ParameterType);
        //
        //
        //            }
        //
        //            // perform the correct call (pushes the result)
        //            emit.callorvirt(method);
        //
        //
        //            if (!method.IsStatic && targetType.IsValueType)
        //                emit.ldarg0().ldloc0().box(targetType).stind_ref();
        //
        //
        //            for (int i = 0; i < prams.Length; i++) {
        //                var paramType = prams[i].ParameterType;
        //                if (paramType.IsByRef)
        //                {
        //                    var byRefType = paramType.GetElementType();
        //                    emit.ldarg1() // stack<= params[]
        //                    .ldc_i4(i) // stack<= i
        //                    .ldloc(i + localVarStart); // stack<= list[i+localVarStart]
        //                    if (byRefType.IsValueType)
        //                        emit.box(byRefType);   // if ex. stack =(object)stack[top]
        //                    emit.stelem_ref(); //  // stack:paramsValuesArray[i]= list[i+localVarStart];
        //                }
        //            }
        //
        //            if (method.ReturnType == typeof(void))
        //                emit.ldnull();
        //            else if (weaklyTyped)
        //                emit.ifvaluetype_box(method.ReturnType);
        //
        //            emit.ret();


    }

Другие вопросы по теме