Friday, April 15, 2011

C#: Accessing Inherited Private Instance Members Through Reflection

I am an absolute novice at reflection in C#. I want to use reflection to access all of private fields in a class, including those which are inherited.

I have succeeded in accessing all private fields excluding those which are inherited, as well as all of the public and protected inherited fields. However, I have not been able to access the private, inherited fields. The following example illustrates:

class A
{
    private string a;
    public string c;
    protected string d;
}

class B : A
{
    private string b;
}

class test
{
    public static void Main(string[] Args)
    {
        B b = new B();       
        Type t;
        t = b.GetType();
        FieldInfo[] fields = t.GetFields(BindingFlags.Public | BindingFlags.NonPublic
                                         | BindingFlags.Instance); 
        foreach(FieldInfo fi in fields){
             Console.WriteLine(fi.Name);
        }
        Console.ReadLine();
    }
}

This fails to find the field B.a.

Is it even possible to accomplish this? The obvious solution would be to convert the private, inherited fields to protected fields. This, however, is out of my control at the moment.

From stackoverflow
  • You can't access the private fields of A using the type of B because those fields don't exist in B - they only exist in A. You either need to specify the type of A directly, or retrieve it via other means (such as getting the base class from the type of B).

    Timwi : Rubbish, of course they exist in B. If they weren't in B, how could a method inherited from A that accesses such a private field work?
    Andy : The instance of B may have A's private members, but the Type of B has no knowledge of such members.
  • I haven't tried it, but you should be able to access the base type private members through the Type.BaseType property and recursively accumulate all the private fields through the inheritence hierarchy.

  • As Lee stated, you can do this with recursion.

    private static void FindFields(ICollection<FieldInfo> fields, Type t) {
     var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
    
     foreach (var field in t.GetFields(flags)) {
      // Ignore inherited fields.
      if (field.DeclaringType == t)
       fields.Add(field);
     }
    
     var baseType = t.BaseType;
     if (baseType != null)
      FindFields(fields, baseType);
    }
    
    public static void Main() {
     var fields = new Collection<FieldInfo>();
     FindFields(fields, typeof(B));
     foreach (FieldInfo fi in fields)
      Console.WriteLine(fi.DeclaringType.Name + " - " + fi.Name);
    }
    
    Timwi : Instead of the "if" clause to ignore inherited fields, you could just specify BindingFlags.DeclaredOnly.
  • You can access private members of Class A from Class B with 'Nested Classes' . You make Class A as Outer Class and Class B as Inner Class

    Class A { ... Class B { ....... }

    }

    Odrade : I'm not able to modify the classes. I'm just trying to garner info about them via reflection.

0 comments:

Post a Comment