Reflection.Emit create an object with parameters

I create a dynamic function to create an object at runtime, taking into account the object [] of constructor parameters. I keep getting the general exception “Operation can destabilize runtime” and I don’t see what I did wrong.

The method works fine if the created object does not need constructor arguments, so the problem should be in the for loop code.

The code indexes the given object [], pushing the object onto the stack, after which ctor is called and the object is returned.

Any ideas ???

internal static Func<object[], object> CreateObjectFactoryMethodWithCtorParams(ConstructorInfo ctor, int ctorArgsLength) { Func<object[], object> factoryMethod = null; if (ctor != null) { var dm = new DynamicMethod(string.Format("_CreationFacotry_{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(object[])}, true); var il = dm.GetILGenerator(); il.DeclareLocal(typeof(int)); il.DeclareLocal(typeof(object)); il.BeginExceptionBlock(); il.Emit(OpCodes.Ldc_I4_0); // [0] il.Emit(OpCodes.Stloc_0); //[nothing] for (int i = 0; i < ctorArgsLength; i++) { EmitInt32(il, i); // [args][index] il.Emit(OpCodes.Stloc_0); // [args][index] il.Emit(OpCodes.Ldarg_0); //[args] EmitInt32(il, i); // [args][index] il.Emit(OpCodes.Ldelem_Ref); // [item-in-args-at-index] } il.Emit(OpCodes.Newobj, ctor); //[new-object] il.Emit(OpCodes.Stloc_1); // nothing il.BeginCatchBlock(ExceptionType); // stack is Exception il.Emit(OpCodes.Ldloc_0); // stack is Exception, index il.EmitCall(OpCodes.Call, EmitGeneratorType.GetMethod("ThrowFactoryException"), null); il.EndExceptionBlock(); il.Emit(OpCodes.Ldloc_1); //[new-object] il.Emit(OpCodes.Ret); factoryMethod = (Func<object[], object>)dm.CreateDelegate(typeof(Func<object[], object>)); } else { throw new EmitGeneratorException("Cannot create instance factory for a null ctor instance"); } return factoryMethod; } private static void EmitInt32(ILGenerator il, int value) { switch (value) { case -1: il.Emit(OpCodes.Ldc_I4_M1); break; case 0: il.Emit(OpCodes.Ldc_I4_0); break; case 1: il.Emit(OpCodes.Ldc_I4_1); break; case 2: il.Emit(OpCodes.Ldc_I4_2); break; case 3: il.Emit(OpCodes.Ldc_I4_3); break; case 4: il.Emit(OpCodes.Ldc_I4_4); break; case 5: il.Emit(OpCodes.Ldc_I4_5); break; case 6: il.Emit(OpCodes.Ldc_I4_6); break; case 7: il.Emit(OpCodes.Ldc_I4_7); break; case 8: il.Emit(OpCodes.Ldc_I4_8); break; default: if (value >= -128 && value <= 127) { il.Emit(OpCodes.Ldc_I4_S, (sbyte)value); } else { il.Emit(OpCodes.Ldc_I4, value); } break; } } 

Call code

  Func<object[], object> factoryFunction = GetFunction(someCtor, new object[] { arg1, arg2}); var obj = factoryFunction(new object[] {new SomeClass, "A String" }); //input ctor args 
+4
source share
1 answer

It works fine for me as long as I do all the parameters of the object constructor:

 class SomeClass { public SomeClass(object s, object t) { } } static void Main() { var someCtor = typeof(SomeClass).GetConstructors()[0]; Func<object[], object> factoryFunction = CreateObjectFactoryMethodWithCtorParams(someCtor, someCtor.GetParameters().Length); var obj = factoryFunction(new object[] {"A String", 123 }); } 

I think the problem is that you did not make any conversions from objects from the array to the actual types of constructors, noting that you need to consider both reference types and value types (unbox). For instance:

 var parameters = ctor.GetParameters(); for (int i = 0; i < parameters.Length ; i++) { EmitInt32(il, i); // [index] il.Emit(OpCodes.Stloc_0); // [nothing] il.Emit(OpCodes.Ldarg_0); //[args] EmitInt32(il, i); // [args][index] il.Emit(OpCodes.Ldelem_Ref); // [item-in-args-at-index] var paramType = parameters[i].ParameterType; if (paramType != typeof(object)) { il.Emit(OpCodes.Unbox_Any, paramType); // same as a cast if ref-type } } il.Emit(OpCodes.Newobj, ctor); //[new-object] il.Emit(OpCodes.Stloc_1); // nothing 

as a minor note: since you need to call .GetParameters() , you should not pass the length of the parameter as a method parameter; which is redundant and can lead to errors when they are wrong.

Then this works with my exmaple:

 class SomeClass { public SomeClass(string s, int t) { } } static void Main() { var someCtor = typeof(SomeClass).GetConstructors()[0]; Func<object[], object> factoryFunction = CreateObjectFactoryMethodWithCtorParams(someCtor); var obj = factoryFunction(new object[] {"A String", 123 }); } 
+5
source

Source: https://habr.com/ru/post/1382389/


All Articles