2

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.

3
  • Have you tried writing the DynamicAssembly to disk and running it through peverify? peverify normally gives good error messages. Commented Jul 26, 2010 at 12:40
  • Is your main goal to create an instance of this concrete type using reflection or actually create THE type during runtime? Commented Jul 26, 2010 at 12:48
  • 2Tim: I cannot save assembly because I use Silverlight. 2Wallace: Yes I must create an instance Commented Jul 27, 2010 at 8:35

2 Answers 2

4

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);
Sign up to request clarification or add additional context in comments.

Comments

3

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.