gpt4 book ai didi

c# 发出动态方法委托(delegate)以加载参数化构造函数问题

转载 作者:太空狗 更新时间:2023-10-30 00:46:47 30 4
gpt4 key购买 nike

我正在尝试通过发出动态方法来创建构造函数的委托(delegate)表示,该方法必须匹配这个非常“松散类型”的签名,以便它可以与任何类型的参数化构造函数一起使用:

public delegate Object ParamsConstructorDelegate(params object[] parameters);

创建委托(delegate)的代码如下所示(注意这是针对 Silverlight 的)

public static ParamsConstructorDelegate CreateDelegate(ConstructorInfo constructor)
{
Guard.ArgumentNotNull(constructor, "constructor");
Guard.ArgumentValue(constructor.GetParameters().Length == 0, MUSTBE_PARAMETERIZED_CONSTRUCTOR);

var _argumentTypes = new Type[] { typeof(object[]) };
var _parameters = constructor.GetParameters();
var _parameterTypes = _parameters.Select((p) => p.ParameterType).ToArray();

var _sourceType = constructor.DeclaringType;
var _method = new DynamicMethod(constructor.Name, _sourceType, _argumentTypes);
var _gen = _method.GetILGenerator();

for (var _i = 0; _i < _parameters.Length; _i++)
{
if (_parameters[_i].IsOut || _parameterTypes[_i].IsByRef)
{
if (_i < 128)
{
_gen.Emit(OpCodes.Ldarga_S, (byte)_i);
}
else
_gen.Emit(OpCodes.Ldarga, _i);
}
else
{
switch (_i)
{
case 0:
_gen.Emit(OpCodes.Ldarg_0, _i);
break;
case 1:
_gen.Emit(OpCodes.Ldarg_1, _i);
break;
case 2:
_gen.Emit(OpCodes.Ldarg_2, _i);
break;
case 3:
_gen.Emit(OpCodes.Ldarg_3, _i);
break;
default:
if (_i < 128)
_gen.Emit(OpCodes.Ldarg_S, (byte)_i);
else
_gen.Emit(OpCodes.Ldarg, _i);
break;
}
}
}
_gen.Emit(OpCodes.Newobj, constructor);
_gen.Emit(OpCodes.Ret); ;

return (ParamsConstructorDelegate)_method.CreateDelegate(typeof(ParamsConstructorDelegate));
}

现在,我收到“操作可能会破坏运行时的稳定性”。验证异常,很明显IL是错误的,所以希望有人指正。

谢谢

最佳答案

我可以看到两个问题;首先,对于 Ldarg_0Ldarg_3 情况,您不需要 _i(它是隐式的)。其次 - 您的委托(delegate)只有 一个参数(数组)。您将需要从数组中取出项目并进行转换 - 如下所示(仅处理按值传递;对于 ref/out 你我必须定义一个本地并使用 STLoc/ldloca/等):

using System;
using System.Reflection.Emit;
public delegate object ParamsConstructorDelegate(params object[] parameters);
public class Foo
{
string s;
int i;
float? f;
public Foo(string s, int i, float? f)
{
this.s = s;
this.i = i;
this.f = f;
}
}

static class Program
{
static void Main()
{
var ctor = Build(typeof(Foo));
Foo foo1 = (Foo)ctor("abc", 123, null);
Foo foo2 = (Foo)ctor(null, 123, 123.45F);
}
static ParamsConstructorDelegate Build(Type type)
{
var mthd = new DynamicMethod(".ctor", type,
new Type[] { typeof(object[]) });
var il = mthd.GetILGenerator();
var ctor = type.GetConstructors()[0]; // not very robust, but meh...
var ctorParams = ctor.GetParameters();
for (int i = 0; i < ctorParams.Length; i++)
{
il.Emit(OpCodes.Ldarg_0);
switch (i)
{
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: il.Emit(OpCodes.Ldc_I4, i); break;
}
il.Emit(OpCodes.Ldelem_Ref);
Type paramType = ctorParams[i].ParameterType;
il.Emit(paramType.IsValueType ? OpCodes.Unbox_Any
: OpCodes.Castclass, paramType);
}
il.Emit(OpCodes.Newobj, ctor);
il.Emit(OpCodes.Ret);
return (ParamsConstructorDelegate)
mthd.CreateDelegate(typeof(ParamsConstructorDelegate));
}
}

有关信息 - 我很懒 - 如果我想知道要编写什么 IL,我会用 C# 编写它,然后将其加载到反射器中。例如,为此我写了一个方法:

static object CreateFoo(object[] vals)
{
return new Foo((string)vals[0], (int)vals[1], (float?)vals[2]);
}

然后从那里反转

关于c# 发出动态方法委托(delegate)以加载参数化构造函数问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2353174/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com