views:

1903

answers:

4

I am wondering, since a lot of things can be done using reflection, can I change a private readonly field after the constructor completed its execution?
(note: just curiosity)

public class Foo
{
 private readonly int bar;

 public Foo(int num)
 {
  bar = num;
 }

 public int GetBar()
 {
  return bar;
 }
}

Foo foo = new Foo(123);
Console.WriteLine(foo.GetBar()); // display 123
// reflection code here...
Console.WriteLine(foo.GetBar()); // display 456
+11  A: 

You can:

typeof(Foo)
   .GetField("bar",BindingFlags.Instance|BindingFlags.NonPublic)
   .SetValue(foo,567);
Philippe Leybaert
+12  A: 

The obvious thing is to try it:

using System;
using System.Reflection;

public class Test
{
    private readonly string foo = "Foo";

    public static void Main()
    {
        Test test = new Test();
        FieldInfo field = typeof(Test).GetField
            ("foo", BindingFlags.Instance | BindingFlags.NonPublic);
        field.SetValue(test, "Hello");
        Console.WriteLine(test.foo);
    }        
}

This works fine. (Java has different rules, interestingly - you have to explicitly set the Field to be accessible, and it will only work for instance fields anyway.)

Jon Skeet
I think this breaks the language specifications, is not it?
Ahmed Said
Ahmed - but we're not using the language to do it, so the language spec doesn't get a vote...
Marc Gravell
Yup - there's a lot that can be done which "breaks" what the language wants. You can run type initializers multiple times, for example.
Jon Skeet
I note also that just because you can in some implementation today does not mean that you can on every implementation for all time. I am not aware of any place where we document that readonly fields must be mutable via reflection. As far as I know, a conforming implementation of the CLI is perfectly free to implement readonly fields such that they throw exceptions when mutated via reflection after the constructor is done.
Eric Lippert
+1  A: 

The answer is yes, but more importantly:

Why would you want to? Intentionally breaking encapsulation seems like a horrifically bad idea to me.

Using reflection to change a readonly or constant field is like combining the Law of Unintended Consequences with Murphy's Law.

R. Bemrose
the answer is "just curiosity", as mentioned above.
Ron Klein
There are times when I find myself having to do just this trick in order to write the best code I can. Case in point - http://elegantcode.com/2008/04/17/testing-a-membership-provider/
CitizenParker
De/Serialization of objects...
Jason
A: 

You asked why you would want to break the encapsulation like that.

I use an entity helper class to hydrate entities. This uses reflection to get all the properties of a new empty entity, and matches the property/field name to the column in the resultset, and set's it using propertyinfo.setvalue().

I don't want anyone else to be able to change the value, but I don't want to take all the effort to custom code hydration methods for every entity either.

My many of my stored procs return resultsets that don't correspond directly to tables or views, so the code gen ORM's do nothing for me.

Necroposter
I've also used it to get past some api limitations where the value was either hardcoded, or required a config file I would be unable to provide. (WSE 2.0 file size for DIME attachments when the assemblies were loaded via reflection, for example)
StingyJack