关于C#:为什么我不能更改string.empty的值?

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

虽然我知道改变String.Empty的值是个坏主意,但我不明白为什么我不能这样做。

要了解我的意思,请考虑以下课程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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());
    }
}

我有一个小的控制台应用程序试图操作这三个只读字段。它可以成功地将蓝色和绿色变为粉红色,但空的保持不变:

1
2
3
4
5
6
7
        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 = }

为什么?

最初,我还问为什么String.Empty不是一个常数。我在另一篇文章中找到了问题的这一部分的答案,并删除了问题的那一部分)。

注意:没有一个"副本"对这个问题有决定性的答案,这就是我问这个问题的原因。


您不能更改它,因为您的计算机上有.NET 4.5。只需将项目的框架目标设置更改为3.5,就可以看到它起作用了。

clr具有string.empty的内置知识。例如,您将看到System.String类从未初始化它的反射器或引用源。它是在clr启动期间完成的。4.5如何阻止修改的可见是有点难说的。您实际上修改了字段,只需添加以下代码行:

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

你会看到"粉色"。我猜它被抖动截获了。不过,我不能提供确凿的证据。有一个先例,尝试修补decimal.maxvalue,例如,另一个只读静态值。在3.5中也不可更改,抖动识别它并直接生成值而不读取字段。

我刚发现你对另一个主题完全相同的问题慷慨相助。280Z28的职位很相似。