我正在使用Reflection类来获取某个对象中的所有字段。 然而,我的问题是,当字段在普通类中时,它可以正常工作,例如:
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)
为什么我从抽象类而不是字段中获取属性的任何想法?
答案 0 :(得分:48)
编辑:要获得基本类型的私有成员,您必须:
typeof(T).BaseType.GetFields(...)
再次编辑:赢。
编辑2013年3月22日:使用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));
}
答案 1 :(得分:4)
继承另一种类型的类型无法看到该其他类型的私有部分,它可以看到受保护的内部和公共部分。请考虑以下代码:
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
类型的私有(字段名称和类型名称的相似性使得该句子有点令人困惑,我担心。)
答案 2 :(得分:3)
您可以使用此扩展方法递归遍历类型的继承层次结构一直到对象,有效地返回该类型及其所有祖先的所有字段:
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)
答案 3 :(得分:2)
属性是继承的,字段不是。受保护的字段对后代类可见,但不会由它们继承。换句话说,后代类实际上具有其基类的属性,但它只能看到字段。
答案 4 :(得分:0)
如果您只想要属性和字段的名称,请使用
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));
}
答案 5 :(得分:0)
枚举所有类型字段,包括基类中的私有成员。
public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
type.BaseType?.EnumerateFields(flags)
.Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
type.EnumerateFields(flags);