22

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

要明白我的意思,请考虑以下课程:

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());
    }
}

我有一个小控制台应用程序,它试图操纵这三个只读字段。它可以成功地将 Blue 和 Green 变成 Pink,但 Empty 保持不变:

        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不是常数。我在另一篇文章中找到了这部分问题的答案,并删除了这部分问题)。

注意:没有一个“重复”对这个问题有明确的答案,这就是我问这个问题的原因。

4

1 回答 1

16

您无法更改它,因为您的机器上有 .NET 4.5。只需将项目的 Framework Target 设置更改为 3.5 即可。

CLR 具有 String.Empty 的内置知识。例如,您将看到 System.String 类从不初始化它的反射器或参考源。它在 CLR 启动期间完成。4.5 究竟是如何防止修改可见的,有点难说。您实际上确实修改了该字段,只需添加以下代码行:

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

你会看到“粉红色”。我的猜测是它被抖动拦截了。但是,我不能为此提供确凿的证据。有先例,例如尝试修改 Decimal.MaxValue,另一个只读静态值。在 3.5 中也无法更改,抖动识别它并直接生成值而不读取字段。

我刚刚发现您在另一个具有完全相同主题的问题上悬赏。280Z28 的帖子非常相似。

于 2013-11-13T22:46:03.483 回答