2010-07-26 3 views
2

я получил следующий базовый класс:Проблема создания типа с отражением

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 обнаружила недействительную программу". Что я делаю не так?

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

+0

Вы пытались написать 'DynamicAssembly' на диск и запустить его через peverify? peverify обычно дает хорошие сообщения об ошибках. –

+0

Ваша главная цель - создать экземпляр этого конкретного типа с использованием отражения или фактически создать тип во время выполнения? –

+0

2Тим: я не могу сохранить сборку, потому что я использую Silverlight. 2Wallace: Да, я должен создать экземпляр – Maxmyd

ответ

4

Когда вы звоните 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); 
+0

Большое спасибо. Это помогло. – Maxmyd

3

Согласно документации к Ldfld, переход стек следующий

  1. Ссылка на объект (или указатель) помещается в стек.
  2. Ссылка на объект (или указатель) выносится из стека; отображается значение указанного поля в объекте.
  3. Значение, хранящееся в поле, помещается в стек.

Таким образом, после выполнения

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

вы будете иметь только ссылку на поле в стеке оценки (без 'это'). Чтобы исправить, дублировать 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); 

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

Смежные вопросы