How to get and set private fields or properties in C#
Sometimes you want to access a private member of an object. If you were the author of such object, you would simply change the encapsulation from private to public, or protected if you just want access from a child. However, what if you don’t have access to the object. What if it is one of the standard .NET library objects. You can’t change it. What are your options?
- Rewrite the entire class. (Not easy and I don’t recommend it)
- Recreate the value somehow (which might not even be possible)
Well, guess what. Microsoft left a nice workaround to encapsulation in its implementation of Reflection.
Here is a nice class you can use to get the value of any private member.
using System; using System.Linq; using System.Reflection; namespace Rhyous.TextBlock.Business { public class PrivateValueAccessor { public static BindingFlags Flags = BindingFlags.Instance | BindingFlags.GetProperty | BindingFlags.SetProperty | BindingFlags.GetField | BindingFlags.SetField | BindingFlags.NonPublic; /// <summary> /// A static method to get the PropertyInfo of a private property of any object. /// </summary> /// <param name="type">The Type that has the private property</param> /// <param name="propertyName">The name of the private property</param> /// <returns>PropertyInfo object. It has the property name and a useful GetValue() method.</returns> public static PropertyInfo GetPrivatePropertyInfo(Type type, string propertyName) { var props = type.GetProperties(Flags); return props.FirstOrDefault(propInfo => propInfo.Name == propertyName); } /// <summary> /// A static method to get the value of a private property of any object. /// </summary> /// <param name="type">The Type that has the private property</param> /// <param name="propertyName">The name of the private property</param> /// <param name="o">The instance from which to read the private value.</param> /// <returns>The value of the property boxed as an object.</returns> public static object GetPrivatePropertyValue(Type type, string propertyName, object o) { return GetPrivatePropertyInfo(type, propertyName).GetValue(o); } /// <summary> /// A static method to get the FieldInfo of a private field of any object. /// </summary> /// <param name="type">The Type that has the private field</param> /// <param name="fieldName">The name of the private field</param> /// <returns>FieldInfo object. It has the field name and a useful GetValue() method.</returns> public static FieldInfo GetPrivateFieldInfo(Type type, string fieldName) { var fields = type.GetFields(Flags); return fields.FirstOrDefault(feildInfo => feildInfo.Name == fieldName); } /// <summary> /// A static method to get the FieldInfo of a private field of any object. /// </summary> /// <param name="type">The Type that has the private field</param> /// <param name="fieldName">The name of the private field</param> /// <param name="o">The instance from which to read the private value.</param> /// <returns>The value of the property boxed as an object.</returns> public static object GetPrivateFieldValue(Type type, string fieldName, object o) { return GetPrivateFieldInfo(type, fieldName).GetValue(o); } } }
And here is how to use it.
Imagine you have a class with a private Field and a private property.
public class A { private int MyPrivateProperty { get { return _MyPrivateField; } set { _MyPrivateField = value; } } private int _MyPrivateField = 27; }
You can access the value as follows:
var a = new A(); // Get values int privateFieldValue = (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", a); int privatePropValue = (int)PrivateValueAccessor.GetPrivatePropertyValue(typeof(A), "MyPrivateProperty", a); // Set Values PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(a, 11); PrivateValueAccessor.GetPrivatePropertyInfo(typeof(A), "MyPrivateProperty").SetValue(a, 7);
Access private fields or properties from a base class
OK, so now that we have this class, you can imagine that you can now use it in a child, if you have no other choice, in order to expose A.MyPrivateProp.
public class B : A { public int ExposedProperty { get { return (int)PrivateValueAccessor.GetPrivateFieldValue(typeof(A), "_MyPrivateField", this); } set { PrivateValueAccessor.GetPrivateFieldInfo(typeof(A), "_MyPrivateField").SetValue(this, value); } } }
Now you have exposed the private value in your child class. You can call it as normal.
var b = new B(); b.ExposedProperty = 20;
Here is what it looks like in the debugger before you set it.
b {B} B base {B} A {B} _MyPrivateField 27 int MyPrivateProperty 27 int ExposedProperty 27 int b.ExposedProperty 27 int
And after setting B.ExposedProperty to 20, it looks like this.
b {B} B base {B} A {B} _MyPrivateField 20 int MyPrivateProperty 20 int ExposedProperty 20 int b.ExposedProperty 20 int
Conclusion
You now have a serviceable workaround for a getting and setting a private field or property.
It really isn’t going to perform well, since it uses Reflection, but if it is a single value that you only set once, you won’t have a performance problem.
Since it is so easy to break encapsulation with Reflection, it makes me wonder what the point of encapsulation is in C#? But it still has it’s purposes, I know.
PrivateValueAccessor.GetPrivatePropertyInfo(typeof(A), "MyProperty").SetValue(a, 7) doesn't work for public property with private setter.
public class A
{
int MyProperty
{
get { return _MyPrivateField; }
private set { _MyPrivateField = value; }
} private int _MyPrivateField = 27;
}
Need add one more method or flag BindingFlags.Public
You have a syntax error:
No overload for method "GetValue" takes 1 arguments
///
/// A static method to get the value of a private property of any object.
///
/// The Type that has the private property
/// The name of the private property
/// The instance from which to read the private value.
/// The value of the property boxed as an object.
public static object GetPrivatePropertyValue(Type type, string propertyName, object o)
{
return GetPrivatePropertyInfo(type, propertyName).GetValue(o);
}
I looked at that. Both PropertyInfo and FieldInfo have this signature available:
public object GetValue(object obj);
Is there a particular DotNet version you are using that is misssing it? When I first wrote this, I was in .Net 4.5.1.