Reflecting a private field from a base class
Here is the structure:
MyClass : SuperClass2
SuperClass2 : SuperClass1
superClass2 is in Product.Web and SuperClass1 is in the .NET System.Web assembly
I'm trying to force a value into a private bool field on SuperClass1. But not matter what I try I cannot get the fields to come back from reflection.
I'm using the following code with different BindingFlag combinations but nothing has worked so far. SuperClass1 is an abstract class.
((SuperClass1)this).GetType().GetFields(System.Reflection.BindingFlags.NonPublic);
Notes: When I use GetProperties() I get back a nice big list but when I specify any bindingflags I get nothing even though there are matching properties. Whats the deal?
Also, the field is not marked internal
Obvisouly I would be using GetField(string name, BindingFlags) but I can't even get GetFlags() to work.
Update: I've tried adding BindingFlags.Instance as suggested but it doesn't work (as expected anyway). I get back 2 fields that are coming from the class SuperClass1 inherits from. Returns null when used with GetField(string name, Flags)
Here is the code for the base class I'm trying to get the field for
public abstract class BaseValidator : Label, IValidator
{
private bool propertiesChecked;
...
}
Solution 1:
You can manually go up in the inheritance chain to get the base fields:
Given these classes:
class SuperClass1
{
private int myField;
}
class SuperClass2 : SuperClass1
{
}
class MyClass : SuperClass2
{
}
This should work:
var myObj = new MyClass();
var myField = typeof(MyClass).BaseType
.BaseType
.GetField("myField", BindingFlags.Instance | BindingFlags.NonPublic);
There's a more generic solution in this SO answer: Not getting fields from GetType().GetFields with BindingFlag.Default
Solution 2:
In a similar vein to BrokenGlass's solution, you could do this to make it a bit more generic:
class Base { private int _baseField; }
class Derived : Base { }
class Mine : Derived { }
And then:
Type t = typeof(Mine);
FieldInfo fi = null;
while (t != null)
{
fi = t.GetField("_baseField", BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null) break;
t = t.BaseType;
}
if (fi == null)
{
throw new Exception("Field '_baseField' not found in type hierarchy.");
}
As a utility method:
public static void SetField(object target, string fieldName, object value)
{
if (target == null)
{
throw new ArgumentNullException("target", "The assignment target cannot be null.");
}
if (string.IsNullOrEmpty(fieldName))
{
throw new ArgumentException("fieldName", "The field name cannot be null or empty.");
}
Type t = target.GetType();
FieldInfo fi = null;
while (t != null)
{
fi = t.GetField(fieldName, BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null) break;
t = t.BaseType;
}
if (fi == null)
{
throw new Exception(string.Format("Field '{0}' not found in type hierarchy.", fieldName));
}
fi.SetValue(target, value);
}
And then:
Mine m = new Mine();
SetField(m, "_baseField", 10);
Solution 3:
Extension method:
/// <summary>
/// Returns the FieldInfo matching 'name' from either type 't' itself or its most-derived
/// base type (unlike 'System.Type.GetField'). Returns null if no match is found.
/// </summary>
public static FieldInfo GetPrivateField(this Type t, String name)
{
const BindingFlags bf = BindingFlags.Instance |
BindingFlags.NonPublic |
BindingFlags.DeclaredOnly;
FieldInfo fi;
while ((fi = t.GetField(name, bf)) == null && (t = t.BaseType) != null)
;
return fi;
}