Super Lloyd Ответов: 0

IL для вызова конструктора на * * существующем * * экземпляре


Я работаю над сериализатор[^] и может случиться так, что мне придется инициализировать объект ISerializable только для чтения.

В настоящее время я успешно делаю это, вызывая конструктор сериализации на существующем экземпляре.

экс:
SerializationInfo info = ....
var ctx = new StreamingContext(StreamingContextStates.Persistence)
var instance = ...
ConstructorInfo ctor = ... find serialization ctor...
ctor.Invoke(instance, new [] { info, ctx });


Прямо сейчас я пытаюсь улучшить общую производительность с помощью System. Emit.
У меня есть некоторый рабочий код (вставленный ниже), который создает быстрый метод отражения.
Я немного взломал код, чтобы вызвать конструктор на существующем экземпляре, но я получаю InvalidProgramException("Common Language Runtime detected an invalid program.")

Итак... как я мог испустить этот трюк конструктора?
(распакованная версия можно найти там[^], для лучшей читабельности...)

Что я уже пробовал:

Я попытался изменить метод emit следующим образом (следите за новым параметром)

излучаемый код:
delegate object MethodHandler(object target, params object[] args);

    static readonly ConstructorInfo SecurityPermissionObjectCtor = typeof(System.Security.Permissions.SecurityPermission).GetTypeInfo().GetConstructor(new Type[] { typeof(System.Security.Permissions.SecurityPermissionFlag) });
    static readonly MethodInfo SecurityPermissionDemand = typeof(System.Security.CodeAccessPermission).GetTypeInfo().GetMethod(nameof(System.Security.CodeAccessPermission.Demand));

    public static MethodHandler CreateMethodHandler(MethodBase method, bool ctorMakeNewObj = true)
    {
        var dynam = new DynamicMethod(string.Empty, typeof(object), ManyObjects, Module, true);
        ILGenerator il = dynam.GetILGenerator();

        if (method.IsConstructor && !ctorMakeNewObj)
        {
            il.Emit(OpCodes.Ldc_I4_4);
            il.Emit(OpCodes.Newobj, SecurityPermissionObjectCtor);
            il.Emit(OpCodes.Call, SecurityPermissionDemand);
        }

        ParameterInfo[] args = method.GetParameters();

        Label argsOK = il.DefineLabel();

        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Ldlen);
        il.Emit(OpCodes.Ldc_I4, args.Length);
        il.Emit(OpCodes.Beq, argsOK);

        il.Emit(OpCodes.Newobj, typeof(TargetParameterCountException).GetTypeInfo().GetConstructor(Type.EmptyTypes));
        il.Emit(OpCodes.Throw);

        il.MarkLabel(argsOK);

        il.PushInstance(method.DeclaringType);

        for (int i = 0; i < args.Length; i++)
        {
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ldc_I4, i);
            il.Emit(OpCodes.Ldelem_Ref);

            il.UnboxIfNeeded(args[i].ParameterType);
        }

        if (method.IsConstructor)
        {
            if (ctorMakeNewObj)
            {
                il.Emit(OpCodes.Newobj, method as ConstructorInfo);
            }
            else
            {
                il.Emit(OpCodes.Call, method as ConstructorInfo);
            }
        }
        else if (method.IsFinal || !method.IsVirtual)
        {
            il.Emit(OpCodes.Call, method as MethodInfo);
        }
        else
        {
            il.Emit(OpCodes.Callvirt, method as MethodInfo);
        }

        Type returnType = method.IsConstructor ? method.DeclaringType : (method as MethodInfo).ReturnType;
        if (returnType != typeof(void))
            il.BoxIfNeeded(returnType);
        else
            il.Emit(OpCodes.Ldnull);

        il.Emit(OpCodes.Ret);

        return (MethodHandler)dynam.CreateDelegate(typeof(MethodHandler));
    }

Mehdi Gholam

О, боль иль испускает!

Не беспокойтесь взгляните на код отражения fastJSON :)

Super Lloyd

Спасибо, что сделал это... (в GitHub)
Я мог только найти код для конструктора без параметров, с помощью NewObj операции! :((

0 Ответов