[ACCEPTED]-Not getting fields from GetType().GetFields with BindingFlag.Default-bindingflags

Accepted answer
Score: 54

Edit: To get private members of the base type, you 4 have to:

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

Edit again: Win.

Edit 3/22/13: Used 3 Concat instead of Union. Since we are specifying BindingFlags.DeclaredOnly and 2 a type's BaseType cannot equal itself, Union is not needed 1 and is more expensive.

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));
}
Score: 4

A type that inherits another type cannot 18 see private parts of that other type, it 17 can see protected, internal and public parts. Consider 16 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 15 is the following:

B Fields:
ProtectedString
A Fields:
PrivateString
ProtectedString

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

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

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

Score: 3

You can use this extension method to recursively 3 traverse a type's inheritance hierarchy 2 all the way up to object, effectively returning 1 all fields of the type and all its ancestors:

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

(Untested, YMMV)

Score: 2

Properties are inherited, fields are not. Protected 5 fields are visible to descendant classes, but 4 not inherited by them. In other words, the 3 descendant class actually has the properties 2 of its base class, but it is just able to 1 see the fields.

Score: 0

If you just want the names for both properties 1 and fields, use

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));
}
Score: 0

Enumeration of all type fields including 1 private members from base classes.

public static IEnumerable<FieldInfo> EnumerateFields(this Type type, BindingFlags flags) =>
   type.BaseType?.EnumerateFields(flags)
       .Concat(type.GetFields(flags | BindingFlags.DeclaredOnly)) ??
   type.EnumerateFields(flags);
Score: 0

Based on Sam's and Steve's answers this 1 is what it worked for me:


public static List<Variance> DetailedCompare<T>(this T val1, T val2)
    {
        try
        {
            List<Variance> variances = new List<Variance>();

            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic |
                                 BindingFlags.Static | BindingFlags.Instance |
                                 BindingFlags.DeclaredOnly;
            FieldInfo[] fi = val1.GetType().GetFields(flags);

            foreach (FieldInfo f in fi)
            {
                var previousValue = f.GetValue(val1);
                var newValue = f.GetValue(val2); 

                if (!Equals(previousValue, newValue))
                {
                    Variance v = new Variance
                    {
                        Prop = f.Name,
                        PreviousValue = previousValue,
                        NewValue = newValue
                    };
                    variances.Add(v);
                }
            }
            return variances;
        }
        catch
        {
            return null;
        }
    }

More Related questions