Guillaume
Guillaume

Reputation: 1802

Why is it possible to change the value of a readonly field but not of a const using reflection?

Why is it possible to modify the value of a readonly field using reflection but not the value of a const?

class Program
{
    static void Main(string[] args)
    {
        Foobar foobar = new Foobar();
        Console.WriteLine(foobar.foo);                   // Outputs "Hello"
        Console.WriteLine(Foobar.bar);                   // Outputs "Hello"

        var field = foobar.GetType().GetField("foo");
        field.SetValue(foobar, "World");                // Ok
        field = foobar.GetType().GetField("bar");
        field.SetValue(foobar, "World");                // Throws FieldAccessException

        Console.ReadKey();
    }
}

public class Foobar
{
    public readonly string foo = "Hello";
    public const string bar = "Hello";
}

I've read this answer so I understand it's allowed to break the rules for readonly but why not for const in that case? I'm sure there's a good reason but I can't figure out what it could be.

-- Edit --

When I take a look at the code above using ildasm, the value of the readonly field is set at compile time. Not on the field itself unlike for the const but in the constructor of the class. So I'm not sure to get why one can be "overwritten" but not the other one.

What I mean is, even if the value of the const is "hard-coded" in the binary, is the reason for not being able to modifiy it a technical limitation in the framework itself because "it's already set" or just a design decision. I don't see any reason why there could not be some "magic" somewhere modifying the const as it's doing it for the readonly.

-- Edit 2 --

To add up to the accepted answer, there is also this other answer which is quite interesting. What I didn't get in the first place when asking this question is that the value behind the const is really replaced anywhere it is used in the code. With this declaration:

public const string Foo = "Hello";

writing later

Console.WriteLine(Foo);

is equivalent to writing

Console.WriteLine("Hello");

Indeed my code

Console.WriteLine(foobar.foo);
Console.WriteLine(Foobar.bar);

is replaced in IL by

IL_0008:  ldfld      string ConsoleApplication3.Foobar::foo
IL_000d:  call       void [mscorlib]System.Console::WriteLine(string)
IL_0012:  nop
IL_0013:  ldstr      "Hello"
IL_0018:  call       void [mscorlib]System.Console::WriteLine(string)

Upvotes: 8

Views: 305

Answers (2)

PSL
PSL

Reputation: 123739

Reason is that the constants are replaced with it value during the compile time itself. But readonly fields are not. You can set a value for a readonly fields either at declaraiotn and/or at that class's constructor. I Hope this answers your question.

Upvotes: 2

ColinE
ColinE

Reputation: 70170

Because const fields are 'set' at compile time, i.e. the compiler replaces the const with the given value during compilation. As a result of the way const values work, their values are copied into every assembly that uses them. Whereas readonly fields are evaluated at runtime.

Upvotes: 9

Related Questions