为什么我不能改变String.Empty的值?

sma*_*man 21 .net c# reflection constants immutability

虽然我明白改变价值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());
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个小的控制台应用程序,试图操纵这三个只读字段.它可以成功地将蓝色和绿色变成粉红色,但是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 = }
Run Code Online (Sandbox Code Playgroud)

为什么?

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

注意:没有任何"重复"有这个问题的结论性答案,这就是我问这个问题的原因.

Han*_*ant 16

您无法更改它,因为您的计算机上有.NET 4.5.只需将项目的Framework Target设置更改为3.5,您就会看到它的工作原理.

CLR具有String.Empty的内置知识.例如,您将看到一个Reflector或Reference Source,System.String类从不初始化它.它是在CLR启动期间完成的.确切地说4.5如何防止修改可见是有点难以辨别的.实际上,你修改字段,只需添加这行代码:

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

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

我刚刚发现你在同一主题的另一个问题上放了一笔赏金.280Z28的帖子非常相似.

  • 我完全不清楚为什么这个问题需要解决.反汇编不会让你到任何地方,你会看到生成的抖动使用的原始地址.哪个不告诉你更多你已经知道的东西,它指向一个空字符串.您将需要v4.5抖动源代码,除非您在Microsoft申请工作,否则无法获得它. (2认同)