25

我正在使用反射类来获取某个对象内的所有字段。但是,我的问题是,当字段位于普通类中时,它可以完美运行,例如:

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)

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

4

6 回答 6

54

编辑:要获取基本类型的私有成员,您必须:

typeof(T).BaseType.GetFields(...)

再次编辑:赢。

编辑 3/22/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));
}
于 2009-07-20T19:47:08.833 回答
4

A type that inherits another type cannot see private parts of that other type, it can see protected, internal and public parts. Consider the following code:

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));

    }
}

The output of this program is the following:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

So, the type A has two fields; PrivateString and ProtectedString. Type B has one; ProtectedString, that it inherits from A. If you wish to "reach" PrivateString through the type B, you will need to navigate to its base type (b.GetType().BaseType).

Note though, that even if the type B reports to have a field called ProtectedString, this field is still not declared in B; it is declared in A. This can be examined by adding BindingFlags.DeclaredOnly to the GetFields calls in the above sample program; GetFields will return no fields for B, and two for A.

Translated to your code sample, this means that the type test3 does not contain the fields test2 and test3, since they are private to the type test2 (the similarity of the field names and type names make that sentence somewhat confusing, I am afraid).a

于 2009-07-20T20:01:31.973 回答
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)

于 2009-07-20T20:09:58.837 回答
2

属性是继承的,字段不是。受保护的字段对后代类可见,但不能被它们继承。换句话说,后代类实际上具有其基类的属性,但它只能看到字段。

于 2009-07-20T19:45:25.780 回答
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));
}
于 2011-01-31T08:01:38.973 回答
0

枚举所有类型字段,包括来自基类的私有成员。

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
于 2017-07-03T21:02:40.993 回答