没有从GetType()获取字段。使用BindingFlag.Default获取GetFields

时间:2009-07-20 19:43:28

标签: c# reflection bindingflags

我正在使用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)

为什么我从抽象类而不是字段中获取属性的任何想法?

6 个答案:

答案 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有两个字段; PrivateStringProtectedString。类型B有一个; ProtectedString,它继承自A。如果您希望通过类型PrivateString“到达”B,则需要导航到其基本类型(b.GetType().BaseType)。

但请注意,即使类型B报告有一个名为ProtectedString的字段,该字段仍未在B中声明;它在A中声明。可以通过将BindingFlags.DeclaredOnly添加到上述示例程序中的GetFields调用来检查这一点; GetFields不会返回任何字段,B将返回两个字段。

转换为您的代码示例,这意味着类型A不包含字段test3test2,因为它们属于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);