Самый простой способ получить все MemberInfos, которые отражают состояние объекта?
Мне нужно получить все члены, которые представляют точное состояние объекта с помощью отражения. Таким образом, эти члены включают поля (FieldInfo
) и авто-свойства (PropertyInfo
). Я могу получить все FieldInfo
с помощью
type.GetFields(); //ok some flags needed here
И получите автоматически реализованные свойства, как указано в этой ссылке:
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....) ?
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
Ответ Джереми - лучшее, что я мог получить. Вот еще один вариант (который я изначально упоминал в самом вопросе):
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 + ">"));
}
Больше объяснения о том, как это работает здесь: /questions/11842174/kak-uznat-yavlyaetsya-li-svojstvo-avtomaticheski-realizovannyim-svojstvom-s-otrazheniem/11842183#11842183
Немного хакерский, но это дает поля и авто-свойства (в отличие от ответа Джереми, который дает только информацию о полях).