使用反射创建类型时出现问题

发布于 2024-09-11 02:36:16 字数 1747 浏览 2 评论 0原文

我得到了以下基类:

public class ValidationItem 
{
    public ObservableCollection<object> GetFilteredValues( ObservableCollection<object> values)
    {
        return new ObservableCollection<object>(); // nothing here yet
    }

}

我创建了一个继承此基类型的类型,并创建了一个 getter,它将返回基类 GetFilteredValues 方法结果。

新属性应该如下所示:

public ObservableCollection<object> Values
{
    get { return GetFilteredValues(_values); }
    set { _values = value; }
}

这就是我所做的:

Type pType = typeof(ObservableCollection<object>);

FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, pType, FieldAttributes.Private);

PropertyBuilder propertyBuilder = tb.DefineProperty( propertyName, PropertyAttributes.HasDefault, pType, null);

MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
                                MethodAttributes.Public |
                                MethodAttributes.SpecialName |
                                MethodAttributes.HideBySig,
                                pType, Type.EmptyTypes);
getPropMthdBldr.SetReturnType(typeof(ObservableCollection<>).MakeGenericType(typeof(object)));
ILGenerator getIL = getPropMthdBldr.GetILGenerator();

MethodInfo minfo = typeof(ValidationItem).GetMethod("GetFilteredValues", new[] { typeof(ObservableCollection<object>) }); // it's not null so everything is ok here

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);

propertyBuilder.SetGetMethod(getPropMthdBldr);

但是每次我运行应用程序并使用此创建的类型时,都会收到错误“公共语言运行时检测到无效程序”。我做错了什么?

提前致谢。

I got a following base class:

public class ValidationItem 
{
    public ObservableCollection<object> GetFilteredValues( ObservableCollection<object> values)
    {
        return new ObservableCollection<object>(); // nothing here yet
    }

}

I create a type which inherits this base type and I create a getter which is going to return a base class GetFilteredValues method result.

This is how a new property should look like:

public ObservableCollection<object> Values
{
    get { return GetFilteredValues(_values); }
    set { _values = value; }
}

This is what I do:

Type pType = typeof(ObservableCollection<object>);

FieldBuilder fieldBuilder = tb.DefineField("_" + propertyName, pType, FieldAttributes.Private);

PropertyBuilder propertyBuilder = tb.DefineProperty( propertyName, PropertyAttributes.HasDefault, pType, null);

MethodBuilder getPropMthdBldr = tb.DefineMethod("get_" + propertyName,
                                MethodAttributes.Public |
                                MethodAttributes.SpecialName |
                                MethodAttributes.HideBySig,
                                pType, Type.EmptyTypes);
getPropMthdBldr.SetReturnType(typeof(ObservableCollection<>).MakeGenericType(typeof(object)));
ILGenerator getIL = getPropMthdBldr.GetILGenerator();

MethodInfo minfo = typeof(ValidationItem).GetMethod("GetFilteredValues", new[] { typeof(ObservableCollection<object>) }); // it's not null so everything is ok here

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);

propertyBuilder.SetGetMethod(getPropMthdBldr);

But each time I run an app and use this created type, I get an error "Common Language Runtime detected an invalid program". What am I doing wrong?

Thanks in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

因为看清所以看轻 2024-09-18 02:36:16

当您调用 GetFilteredValues 时,堆栈上唯一的东西就是 ObservableCollection。由于 GetFilteredValues 是一个实例方法,因此您还需要推送 this。在现有的 Ldarg_0 之前添加第二个 Ldarg_0,以便在 _values 之前将其压入堆栈:

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);

When you call GetFilteredValues, the only thing on the stack is the ObservableCollection<object>. Since GetFilteredValues is an instance method, you also need to push this. Add a second Ldarg_0 before the existing one so that you push it on the stack before _values:

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);
灯下孤影 2024-09-18 02:36:16

根据 Ldfld 的文档,堆栈转换是将

  1. 对象引用(或指针)压入堆栈。
  2. 对象引用(或指针)从堆栈中弹出;找到对象中指定字段的值。
  3. 存储在该字段中的值被压入堆栈。

因此,执行后,

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);

您在计算堆栈上将只有字段引用(没有“this”)。要修复此问题,请复制 arg_0

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);

这应该会有所帮助。

As per documentation to Ldfld, stack transition is the following

  1. An object reference (or pointer) is pushed onto the stack.
  2. The object reference (or pointer) is popped from the stack; the value of the specified field in the object is found.
  3. The value stored in the field is pushed onto the stack.

So after executing

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);

you will have only field reference on the evaluation stack (without 'this'). To fix, duplicate arg_0

getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Dup);
getIL.Emit(OpCodes.Ldfld, fieldBuilder);
getIL.EmitCall(OpCodes.Callvirt, minfo, Type.EmptyTypes);
getIL.Emit(OpCodes.Ret);

This should help.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文