Проблема создания типа с отражением - PullRequest
2 голосов
/ 26 июля 2010

У меня следующий базовый класс:

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

}

Я создаю тип, который наследует этот базовый тип, и я создаю метод получения, который будет возвращать результат метода базового класса 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);

Но каждый раз, когда я запускаю приложение и использую этот созданный тип, я получаю сообщение об ошибке «Common Language Runtime обнаружил недопустимую программу». Что я делаю не так?

Заранее спасибо.

Ответы [ 2 ]

4 голосов
/ 26 июля 2010

Когда вы вызываете GetFilteredValues, единственная вещь в стеке - ObservableCollection<object>. Поскольку GetFilteredValues является методом экземпляра, вам также нужно нажать this. Добавьте второй 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);
3 голосов
/ 26 июля 2010

В соответствии с документацией к 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);

Это должно помочь.

...