简体   繁体   中英

Why can't I change the value of String.Empty?

While I understand that changing the value of String.Empty would be a bad idea, I don't understand why I can't do it.

To get what I mean, consider the following class:

public class SomeContext 
{ 
    static SomeContext(){}
    public static readonly string Green = "Green";
    public static readonly SomeContext Instance = new SomeContext();

    private SomeContext(){}
    public readonly string Blue = "Blue";

    public static void PrintValues()
    { 
        Console.WriteLine(new { Green, Instance.Blue, String.Empty }.ToString());
    }
}

I have a little console app that tries to manipulate these three readonly fields. It can successfully make Blue and Green into Pink, but Empty stays the same:

        SomeContext.PrintValues();
        ///  prints out : { Green = Green, Blue = Blue, Empty = }
        typeof(SomeContext).GetField("Blue").SetValue(SomeContext.Instance, "Pink");
        typeof(SomeContext).GetField("Green", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Pink");
        typeof(String).GetField("Empty", BindingFlags.Public | BindingFlags.Static).SetValue(null, "Pink");
        SomeContext.PrintValues();
        ///  prints out : { Green = Pink, Blue = Pink, Empty = }

Why?

Originally, I also asked why String.Empty wasn't a constant. I found the answer to this part of my question on another post and deleted that part of the question).

Note: None of the "duplicates" have a conclusive answer to this problem, that's why I'm asking this question.

You can't change it because you have .NET 4.5 on your machine. Just change the Framework Target setting of your project to 3.5 and you'll see it works.

The CLR has built-in knowledge of String.Empty. You'll for example see with a Reflector or the Reference Source that the System.String class never initializes it. It is done during CLR startup. Exactly how 4.5 prevents the modification from being visible is a bit hard to tell. You actually did modify the field, just add this line of code:

  var s = typeof(String).GetField("Empty", 
             BindingFlags.Public | BindingFlags.Static).GetValue(null);
  Console.WriteLine(s);

And you'll see "Pink". My guess is that it is intercepted by the jitter. I can't give hard evidence for that however. There's precedent, try tinkering with Decimal.MaxValue for example, another readonly static value. Not changeable in 3.5 either, the jitter recognizes it and generates the value directly without reading the field.

I just found out you put a bounty on another question with the exact same subject. 280Z28's post is pretty similar.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM