开发者

Problem creating type with Reflection

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(O开发者_JAVA百科bservableCollection<>).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.


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);


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜