I am working on a
serializer[
^] and it might happen that I have to initialize a readonly ISerializable object.
Currently I successfully do it by calling the serialization constructor on the existing instance.
ex:
SerializationInfo info = ....
var ctx = new StreamingContext(StreamingContextStates.Persistence)
var instance = ...
ConstructorInfo ctor = ... find serialization ctor...
ctor.Invoke(instance, new [] { info, ctx });
Right now I am trying to improve overall performance with System.Emit.
I have some working code (pasted below) that create fast reflection method.
I hacked the code a bit to call constructor on existing instance but I get the an
InvalidProgramException("Common Language Runtime detected an invalid program.")
So.. how could I emit this constructor trick?
(unhacked version
can be found there[
^], for better readability...)
What I have tried:
I have tried to change the emit method as follow (watch for new parameter)
emitted code:
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));
}