50

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:
Cemafor
  • 1,633
  • 12
  • 27
Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • Could you specify "not working"? What happens, and how does that differ from what you expect? Do you get any error message? – Guffa Oct 21 '12 at 00:48
  • Try itterating through GetFields() (manually using debugger breakpoint) to see what is returned. Afaik, there is no guarantee that the variable id will stay named id, but I'm not sure. Also, I've had problems getting private properties/methods before, and it's generally solved by using BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance (for instance) – Alxandr Oct 21 '12 at 00:55

3 Answers3

106

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.

Community
  • 1
  • 1
nick_w
  • 14,758
  • 3
  • 51
  • 71
  • unfortunately this doesn't work for structures. it seams to set value of structure copy sent to SetValue, and original structure remains unchanged. – SoLaR Nov 23 '17 at 09:40
  • 2
    According to Jon Skeet, the correct way to set a struct requires explicit boxing before calling SetValue: https://stackoverflow.com/questions/6280506/is-there-a-way-to-set-properties-on-struct-instances-using-reflection – JamesHoux Aug 28 '19 at 00:53
1

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]
> 
riQQ
  • 9,878
  • 7
  • 49
  • 66
Alxandr
  • 12,345
  • 10
  • 59
  • 95
1

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; }
}
DaemonFire
  • 573
  • 6
  • 13