Set value of private field

Why is the following code not working:

class Program { static void Main ( string[ ] args ) { SomeClass s = new SomeClass( ); s.GetType( ).GetField( "id" , System.Reflection.BindingFlags.NonPublic ) // sorry reasently updated to GetField from GetProperty... .SetValue( s , "new value" ); } } class SomeClass { object id; public object Id { get { return id; } } } 

I am trying to set the value of a private field.


Here is the exeption I get:

 System.NullReferenceException was unhandled Message=Object reference not set to an instance of an object. Source=ConsoleApplication7 StackTrace: at Program.Main(String[] args) in C:\Users\Antonio\Desktop\ConsoleApplication7\ConsoleApplication7\Program.cs:line 18 at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly() at System.Threading.ThreadHelper.ThreadStart_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart() InnerException: 
2

4 Answers

Try this (inspired by Find a private field with Reflection?):

var prop = s.GetType().GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); prop.SetValue(s, "new value"); 

My changes were to use the GetField method - you are accessing a field and not a property, and to or NonPublic with Instance.

2

If you want a faster alternative consider using expression trees or Unsafe.As<T>. In testing reflection can be anywhere between 30x to 100x times slower than either technique.

Expression tree

static Action<TSource, TArg> BuildSetterExpression<TSource, TArg>(FieldInfo field) { var inputObject = Expression.Parameter(typeof(TSource)); var valueToSet = Expression.Parameter(typeof(TArg)); var fieldInformation = Expression.Field(inputObject, field); var fieldAssignment = Expression.Assign(fieldInformation, valueToSet); return Expression.Lambda<Action<TSource, TArg>>(fieldAssignment, inputObject, valueToSet).Compile(); } var fieldInfo = typeof(MyClass).GetField("_num", BindingFlags.NonPublic | BindingFlags.Instance); var setNumFunc = BuildSetterExpression<MyClass, int>(fieldInfo); var instance = new MyClass(); setNumFunc(instance, 123); Assert.Equal(123, instance.Num); class MyClass { private int _num = 12; public int Num => _num; } 

Unsafe.As<T>

If you know the structure of the object you're accessing and don't mind using unsafe code use Unsafe.As<T>

var source = new SourceClass(); var target = Unsafe.As<TargetClass>(source); target.Num = 123; Assert.Equal(123, source.GetPrivateNum); class SourceClass { private int _num = 12; public int GetPrivateNum => _num; } class TargetClass { public int Num { get; set; } } 

Evidently, adding BindingFlags.Instance seems to have solved it:

> class SomeClass { object id; public object Id { get { return id; } } } > var t = typeof(SomeClass) ; > t [Submission#1+SomeClass] > t.GetField("id") null > t.GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); > t.GetField("id", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) [System.Object id] > 

Extending Nick's answer:

 public static void SetPrivateField<T, T2>(this T item, string fieldName, T2 newValue) { var field = item.GetType().GetField(fieldName, BindingFlags.NonPublic, | BindingFlags.Instance); field.SetValue(item, newValue); } 

To use this:

someClassInstance.SetPrivateField("id", "newValue"); //realizes the type T2 by the fact "newValue" is a string. //probably doesn't work on readonly, haven't tried. 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like