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" });
source share