Не получает поля из GetType().GetFields с помощью BindingFlag.По умолчанию
-
18-09-2019 - |
Вопрос
Я использую классы отражения для того, чтобы получить все поля внутри определенного объекта.Моя проблема, однако, заключается в том, что это отлично работает, когда поля находятся внутри обычного класса, например:
class test
{
string test1 = string.Empty;
string test2 = string.Empty;
}
Здесь я получаю как test1, так и test2, моя проблема в том, что я использую абстракцию и, таким образом, объединяю несколько классов.
У меня получилось что-то вроде:
class test3 : test2
{
string test4 = string.Empty;
string test5 = string.Empty;
}
class test2 : test1
{
string test2 = string.Empty;
string test3 = string.Empty;
}
class test1
{
string test0 = string.Empty;
string test1 = string.Empty;
}
Но когда я запускаю его, я не получаю поля обратно из GetType().GetFields(BindingFlag.Default)
.
У каждого из этих полей также есть свойство, get; set;
привязанный к нему.Когда я запускаю код, я получаю свойства вплоть до test1, но не фактические поля.
Это код, с помощью которого я пытаюсь получить поля:
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Default);
foreach (FieldInfo field in fields)
Я тоже пытался:
FieldInfo[] fields = Obj.GetType().GetFields(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
Я использую тот же код для свойств:
PropertyInfo[] properties = Obj.GetType().GetProperties(BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.NonPublic
| BindingFlags.Static);
foreach (PropertyInfo property in properties)
Есть какие-нибудь идеи, почему я получаю свойства из абстрактных классов, но не из полей?
Решение
Редактировать:Чтобы получить Частное члены базового типа, вы должны:
typeof(T).BaseType.GetFields(...)
Отредактируйте еще раз:Конкурсы.
Редактировать 22.03.13:Использованный Concat
вместо того , чтобы Union
.Поскольку мы указываем BindingFlags.DeclaredOnly
и типажи BaseType
не может сравниться с самим собой, Union
не нужен и стоит дороже.
public static IEnumerable<FieldInfo> GetAllFields(Type t)
{
if (t == null)
return Enumerable.Empty<FieldInfo>();
BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
BindingFlags.Static | BindingFlags.Instance |
BindingFlags.DeclaredOnly;
return t.GetFields(flags).Concat(GetAllFields(t.BaseType));
}
Другие советы
Тип, наследующий другой тип, не может видеть закрытые части этого другого типа, он может видеть защищенные, внутренние и общедоступные части.Рассмотрим следующий код:
class A
{
// note that this field is private
string PrivateString = string.Empty;
// protected field
protected string ProtectedString = string.Empty;
}
class B : A { }
class Program
{
static void Main(string[] args)
{
Console.WriteLine("B Fields:");
B b = new B();
b.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.ToList()
.ForEach(f => Console.WriteLine(f.Name));
Console.WriteLine("A Fields:");
A a = new A();
a.GetType()
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
.ToList()
.ForEach(f => Console.WriteLine(f.Name));
}
}
Результатом работы этой программы является следующее:
B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString
Итак, тип A
имеет два поля; PrivateString
и ProtectedString
.Тип B
имеет один; ProtectedString
, что он наследует от A
.Если вы хотите "достичь" PrivateString
через тип B
, вам нужно будет перейти к его базовому типу (b.GetType().BaseType
).
Однако обратите внимание, что даже если тип B
сообщает, чтобы поле называлось ProtectedString
, это поле все еще не объявлено в B
;это объявлено в A
.Это можно проверить, добавив BindingFlags.DeclaredOnly
к тому GetFields
вызовы в приведенном выше примере программы; GetFields
не вернет никаких полей для B
, и два для A
.
Переведенный в ваш пример кода, это означает, что тип test3
не содержит полей test2
и test3
, поскольку они являются частными для типа test2
(боюсь, сходство названий полей и типов делает это предложение несколько запутанным).a
Вы можете использовать этот метод расширения для рекурсивного обхода иерархии наследования типа вплоть до object, эффективно возвращая все поля типа и всех его предков:
public static class ReflectionExtensions
{
public static IList<FieldInfo> GetAllFields(this Type type, BindingFlags flags)
{
if(type == typeof(Object)) return new List<FieldInfo>();
var list = type.BaseType.GetAllFields(flags);
// in order to avoid duplicates, force BindingFlags.DeclaredOnly
list.AddRange(type.GetFields(flags | BindingFlags.DeclaredOnly));
return list;
}
}
(Непроверенный, YMMV)
Свойства наследуются, поля - нет.Защищенные поля видны классам-потомкам, но не наследуются ими.Другими словами, класс-потомок на самом деле обладает свойствами своего базового класса, но он способен видеть только поля.
Если вам просто нужны имена как для свойств, так и для полей, используйте
private static IEnumerable<string > GetAllFieldsAndProperties(Type t)
{
if (t == null)
return Enumerable.Empty<string>();
BindingFlags flags = BindingFlags.Public
| BindingFlags.NonPublic
| BindingFlags.Static
| BindingFlags.Instance
| BindingFlags.DeclaredOnly;
return t.GetFields(flags).Select(x=>x.Name)
.Union(GetAllFieldsAndProperties(t.BaseType))
.Union(t.GetProperties(flags).Select(x=>x.Name));
}
Перечисление всех полей типа, включая закрытые элементы из базовых классов.
public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
type.BaseType?.EnumerateFields(flags)
.Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
type.EnumerateFields(flags);