2013-05-12 4 views
1

Мне нужно получить все элементы, которые представляют точный состояние объекта с использованием отражения. Таким образом, эти члены включают поля (FieldInfo) и авто-свойства (PropertyInfo). Я могу получить все FieldInfo с с помощьюПростейший способ получить все элементы MemberInfos, которые отражают состояние объекта?

type.GetFields(); //ok some flags needed here 

И получить авто реализованы свойства, как указано в этом link:

public static bool MightBeCouldBeMaybeAutoGeneratedInstanceProperty(this PropertyInfo info) 
{ 
    bool mightBe = info.GetGetMethod().HasCompilerGeneratedAttribute(); 
    if (!mightBe) 
     return false; 

    bool maybe = info.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) 
            .Where(f => f.Name.Contains(info.Name)) 
            .Where(f => f.Name.Contains("BackingField")) 
            .Where(f => f.HasCompilerGeneratedAttribute()) 
            .Any(); 

    return maybe; 
} 

public static bool HasCompilerGeneratedAttribute(this MemberInfo mi) 
{ 
    return mi.GetCustomAttributes(typeof(CompilerGeneratedAttribute), true).Any(); 
} 

Как Отвечающий говорит, что это действительно хрупкими. Существует ли более стандартный способ достижения этого? Я думаю, может быть что-то с BindingFlags или так?

type.GetMembers(BindingFlags....) ? 
+0

это для определенных типов объектов или для любого типа объекта? если вы хотите получить состояние для определенных типов, и вы владеете их кодом, вы можете добавить свой собственный специальный атрибут [ObjectState], чтобы пометить эти поля –

+0

@omerschleifer для любого типа объекта. Я подумываю о том, чтобы обращаться с ним в общем, чем идти и модифицировать все эти классы. – nawfal

+0

Нужно ли относиться к полям свойств авто-собственности иначе, чем к обычным полям? По моему опыту, «GetFields (BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);» захватят их. Или я не понимаю вопрос? –

ответ

2

Если под «точным состоянием объекта» просто означает все инстанции поле содержит (если нет, то вы можете уточнить?), То вы должны быть в состоянии сделать это с помощью одного оператора - есть нет существенной разницы между полями, которые вы декларируете явно, и резервные поля для авто-свойств, которые компилятор добавляет для вас. Если вы определяете класс:

public class FieldInfoTest 
{ 
    private string testField; 

    public string TestProperty { get; set; } 
} 

... Вы можете получить доступ к ним все в одном махом с

FieldInfo[] fields = typeof(FieldInfoTest).GetFields(BindingFlags.Instance | 
                BindingFlags.Public | 
                BindingFlags.NonPublic); 

foreach (var f in fields) 
{ 
    Console.WriteLine(f.Name); 
} 

Это даст:

testField 
<TestProperty>k__BackingField 
+0

Джереми, +1 за идею, может работать в моем случае. Но я хотел бы получить свойство вместо этого (как 'PropertyInfo') – nawfal

+0

@nawfal Любая конкретная причина, по которой у вас есть особый интерес к авто-свойствам? Я имею в виду, что, помимо того, что они реализованы с помощью сахара-компилятора, они почти такие же, как и обычные свойства под капотом. –

+0

В моем случае мне нужен дескриптор autoproperties для того, что они являются автономным членом (по крайней мере из внешнего мира), но не нормальными свойствами (которые будут иметь поле поддержки).Например, если класс 'Person' выглядит следующим образом:' int age; int Age {get {return age; }} string Имя {get; задавать; } ', что все определяет конкретное состояние объекта? Это должны быть поля (поскольку они составляют основу свойств, внешне - что-то другое) и авто-свойства, которые не имеют полей поддержки - следовательно, «возраст» и «имя» для меня. – nawfal

0

ответ Джереми является лучшим я мог достать. Вот еще одна альтернативы (который я первоначально упомянул в самом вопросе):

public static IEnumerable<MemberInfo> GetStateMembers(this Type t) 
{ 
    return t.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) 
      .Where(m => m.MemberType == MemberTypes.Field && !((FieldInfo)m).Name.Contains('<') 
        || m.MemberType == MemberTypes.Property && ((PropertyInfo)m).IsAutoProperty()); 
} 

public static bool IsAutoProperty(this PropertyInfo prop) 
{ 
    if (!prop.CanWrite || !prop.CanRead) 
     return false; 

    return prop.DeclaringType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance) 
          .Any(f => f.Name.Contains("<" + prop.Name + ">")); 
} 

Более объяснение о том, что работает здесь: https://stackoverflow.com/a/16506710/661933

Немного хак, но это дает поля и авто-свойство (в отличие от ответа Джереми, который дает только полевую информацию).