Reflection.Emit 创建带有参数的对象
我正在创建一个动态函数,以便在给定构造函数参数的 object[] 的情况下在运行时创建一个对象。我不断收到通用异常“操作可能会破坏运行时的稳定性”,但我看不出我做错了什么。
如果创建的对象不需要构造函数参数,则该方法可以正常工作 - 因此问题一定出在 for 循环的代码中。
代码索引到给定的 object[] 中,将对象放入堆栈中,然后调用 ctor 并返回对象。
有什么想法吗???
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;
}
}
调用代码
Func<object[], object> factoryFunction = GetFunction(someCtor, new object[] { arg1, arg2});
var obj = factoryFunction(new object[] {new SomeClass, "A String" }); //input ctor args
I'm creating a dynamic function to create an object at runtime given an object[] of constructor params. I keep getting the generic exception 'Operation could destablise the runtime' and I can't see what I've done wrong.
The method works fine if the created object needs no constructor arguments - so the problem must be in the code in the for loop.
The code indexes into the given object[] putting the object onto the stack after which the ctor is called and the object 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;
}
}
Calling code
Func<object[], object> factoryFunction = GetFunction(someCtor, new object[] { arg1, arg2});
var obj = factoryFunction(new object[] {new SomeClass, "A String" }); //input ctor args
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
只要我将所有构造函数参数设置为
object
,它对我来说就很好用:我认为问题是您尚未完成从数组中的对象到实际构造函数类型的任何转换,请注意您需要考虑引用类型和值类型(拆箱)。像这样:
作为一个小注意事项:由于您需要调用
.GetParameters()
,因此您不应该不将参数长度作为参数传递给方法;这是多余的,错误时可能会导致错误。然后这适用于我的例子:
It works fine for me, as long as I make all the constructor parameters
object
:I think the problem is that you haven't done any conversions from the objects from the array to the actual constructor types, noting that you need to consider both reference types and value-types (unbox). Like so:
as a minor note: since you need to call
.GetParameters()
, you should not pass in the parameter length as a parameter to the method; that is redundant, and could cause errors when wrong.This then works with my exmaple: