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 операции! :((