2013-11-20 4 views
5

Я столкнулся с проблемой, которая не решена общедоступными решениями, по-видимому, одной и той же проблемой.Получить атрибут от динамически генерируемого класса

Рассмотрим:

У меня есть набор динамически создаваемых классов, наследуя от известного базового класса (назовем его BaseClass). Эти динамически генерируемые классы также динамически генерируют Properties со связанными атрибутами.

Атрибуты также из пользовательского класса, хотя и не генерируются динамически:

[AttributeUsage(AttributeTargets.Property)] 
class TypeAttribute: Attribute 
{ 
    private Type _type; 
    public Type Type 
    { 
     get { return _type; } 
    } 

    public TypeAttribute(Type t) 
    { 
     _type = t; 
    } 
} 

Тогда я хочу, во время выполнения, конечно, получить значение этого назначенного атрибута:

List<PropertyInfo> result = target.GetType() 
    .GetProperties() 
    .Where(
    p => 
     p.GetCustomAttributes(typeof(TypeAttribute), true) 
     //.Where(ca => ((TypeAttribute)ca).) 
     .Any() 
    ) 
    .ToList(); 

где target является подклассом BaseClass. Однако список result пуст, и это меня озадачивает.

добавить атрибут с помощью

PropertyBuilder propertyBuilder = tb.DefineProperty(propertyName, 
      PropertyAttributes.HasDefault, propertyType, null); 
ConstructorInfo classCtorInfo = typeof(TypeAttribute). 
      GetConstructor(new Type[] { typeof(Type) }); 
CustomAttributeBuilder myCABuilder = new CustomAttributeBuilder(
      classCtorInfo, new object[] { getType(dataType) }); 
propertyBuilder.SetCustomAttribute(myCABuilder); 

где dataType типа для хранения в атрибуте и tb является TypeBuilder для класса.

Если у меня есть getCustomAttributes(), я получаю ожидаемые атрибуты, кроме тех, которые я ищу. Но если я делаю getCustomAttributesData(), я получаю все из них, но тот, который я ищу, имеет тип CustomAttributeData и не может быть отнесен к TypeAttribute (если я исследую экземпляр в отладчике VS, я могу видеть, что содержащаяся информация относится к TypeAttribute). Я предполагаю, что это симптом проблемы, но я не могу найти причину - и тем более решение.

Может кто-нибудь указать мне, почему список result пуст?

+0

ooh, это весело; для меня потребуется несколько минут, чтобы создать тестовую установку ... Я надеюсь, что кто-то обнаружит что-то очевидное, пока я это делаю! –

ответ

1

Прекрасно работает для меня; вы уверены, что ваша собственность и метод (-ы) getter или setter существуют достаточно, чтобы на самом деле это отображалось как свойство?

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Reflection; 
using System.Reflection.Emit; 
[AttributeUsage(AttributeTargets.Property)] 
public class TypeAttribute : Attribute 
{ 
    private Type _type; 
    public Type Type 
    { 
     get { return _type; } 
    } 

    public TypeAttribute(Type t) 
    { 
     _type = t; 
    } 
} 

public class BaseClass 
{ 

} 

static class Program 
{ 
    static void Main() 
    { 
     var aName = new AssemblyName("MyAssembly"); 
     var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(
       aName, AssemblyBuilderAccess.RunAndSave); 
     var mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll"); 
     var tb = mb.DefineType("MyType", TypeAttributes.Public, typeof(BaseClass)); 

     var propertyName = "MyProperty"; 
     var propertyType = typeof(int); 
     var propertyBuilder = tb.DefineProperty(propertyName, 
      PropertyAttributes.HasDefault, propertyType, null); 
     var classCtorInfo = typeof(TypeAttribute). 
        GetConstructor(new Type[] { typeof(Type) }); 

     Type tArg = typeof(float); // for no real reason 
     var myCABuilder = new CustomAttributeBuilder(
      classCtorInfo, new object[] { tArg }); 
     propertyBuilder.SetCustomAttribute(myCABuilder); 

     var field = tb.DefineField("myField", propertyType, FieldAttributes.Private); 
     var getter = tb.DefineMethod("get_" + propertyName, 
      MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Public, 
      propertyType, Type.EmptyTypes); 
     propertyBuilder.SetGetMethod(getter); 
     var il = getter.GetILGenerator(); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Ldfld, field); 
     il.Emit(OpCodes.Ret); 
     var setter = tb.DefineMethod("set_" + propertyName, 
      MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.Public, 
      typeof(void), new[] { typeof(int) }); 
     il = setter.GetILGenerator(); 
     il.Emit(OpCodes.Ldarg_0); 
     il.Emit(OpCodes.Ldarg_1); 
     il.Emit(OpCodes.Stfld, field); 
     il.Emit(OpCodes.Ret); 
     propertyBuilder.SetSetMethod(setter); 
     var target = Activator.CreateInstance(tb.CreateType());   

     List<PropertyInfo> result = target.GetType() 
      .GetProperties() 
      .Where(
      p => 
       p.GetCustomAttributes(typeof(TypeAttribute), true) 
       //.Where(ca => ((TypeAttribute)ca).) 
       .Any() 
      ).ToList(); 
    } 
} 

Кроме того, более эффективно использовать Attribute.IsDefined если вы просто все равно, что он выходит.

List<PropertyInfo> result = target.GetType().GetProperties() 
     .Where(p => Attribute.IsDefined(p, typeof(TypeAttribute), true)).ToList(); 

Заметим также, что я должен был подменить getType(dataType) вещи - я не мог видеть, что это делает, поскольку он не был в этом вопросе. Убедитесь, что он возвращает Type.

+0

Это сработало, как вы говорите. Я чувствую себя немного глупо, потому что раньше не пытался запускать его в отдельной проблеме, но я все равно буду здесь, но с другим вопросом. Но, когда я копирую этот рабочий код в свое «реальное» приложение, он не будет работать. результатом является список нулевой длины. Тот же код скопирован в приложение WPF. Чтобы исключить WPF, являющегося виновником, я также создал и пуст WPF-приложение, которое сработало. Так что это что-то в моем «реальном приложении». Проблема заключается в том, что ... – fredrik

+0

Такая глупая ошибка. Очевидно, забывая объявить 'TypeAttribute' как общедоступный, это вызовет это.Не заметил это без вашего рабочего кода. Благодарю. – fredrik

+0

Когда я пытаюсь сделать 'result [0] .GetCustomAttributes()' Я получаю «FileNotFoundException» на автогенерируемой сборке. Понял, что мне нужно делать? (ofc проверить, что в списке есть хотя бы один результат) – fredrik

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