c# - 更改了 .NET 4.5 中 string.Empty(或 System.String::Empty)的行为

标签 c# .net .net-4.5 readonly string

短版:

C# 代码

typeof(string).GetField("Empty").SetValue(null, "Hello world!");
Console.WriteLine(string.Empty);

编译并运行时,给出输出 "Hello world!"在 .NET 4.0 及更早版本下,但提供 ""在 .NET 4.5 和 .NET 4.5.1 下。

如何像这样忽略对字段的写入,或者谁重置该字段?

加长版:

我从来没有真正理解为什么 string.Empty字段(也称为 [mscorlib]System.String::Empty )不是 const (又名 literal),参见“Why isn't String.Empty a constant?”。这意味着,例如,在 C# 中我们不能使用 string.Empty在以下情况下:
  • switch声明形式 case string.Empty:
  • 作为可选参数的默认值,如 void M(string x = string.Empty) { }
  • 应用属性时,例如 [SomeAttribute(string.Empty)]
  • 需要编译时常量的其他情况

  • 这对众所周知的“宗教 war ”是否使用string.Empty有影响或 "" ,见“In C#, should I use string.Empty or String.Empty or "" to intitialize a string?”。

    几年前,我通过设置 Empty 自娱自乐。通过反射到其他一些字符串实例,看看 BCL 的多少部分因此开始表现异常。这是相当多的。和Empty的变化引用似乎在应用程序的整个生命周期中都存在。现在,前几天我试图重复那个小特技,但后来使用了 .NET 4.5 机器,我再也做不到了。

    (注意!如果你的机器上有 .NET 4.5,可能你的 PowerShell 仍然使用旧版本的 .NET(编辑:仅适用于 Windows 7 或更旧版本,其中 PowerShell 没有更新到 PowerShell 2.0 以上),所以尝试复制-将 [String].GetField("Empty").SetValue($null, "Hello world!") 粘贴到 PowerShell 中以查看更改此引用的一些效果。)

    当我试图寻找原因时,我偶然发现了有趣的线程“What's the cause of this FatalExecutionEngineError in .NET 4.5 beta?”。在该问题的公认答案中,是否注意到通过 4.0 版,System.String有一个静态构造函数 .cctor其中领域Empty已设置(在 C# 源代码中,当然,这可能只是一个字段初始值设定项),而在 4.5 中不存在静态构造函数。在这两个版本中,字段本身看起来是一样的:
    .field public static initonly string Empty
    

    (如 IL DASM 所见)。

    String::Empty 外没有其他字段似乎受到了影响。作为一个例子,我试验了 System.Diagnostics.Debugger::DefaultCategory .这种情况看起来很相似:一个包含 static readonly 的密封类( static initonly ) string 类型的字段.但是在这种情况下,通过反射更改值(引用)可以正常工作。

    回到问题:

    从技术上讲,Empty 怎么可能?当我设置字段时,似乎没有改变(在 4.5 中)?我已经验证 C# 编译器不会在读取时“作弊”,它输出 IL 如下:
    ldsfld     string [mscorlib]System.String::Empty
    

    所以应该阅读实际的领域。

    在对我的问题进行悬赏后编辑:请注意,写操作(肯定需要反射,因为字段是 readonly(在 IL 中又名 initonly))实际上按预期工作。它是 阅读 异常的操作。如果你用反射阅读,如 typeof(string).GetField("Empty").GetValue(null) ,一切正常(即看到值的变化)。请参阅下面的评论。

    所以更好的问题是:为什么这个新版本的框架在读取这个特定字段时会作弊?

    最佳答案

    不同之处在于新版本 .NET 的 JIT,它显然优化了对 String.Empty 的引用。通过内联对特定 String 的引用实例而不是加载存储在 Empty 中的值 field 。这在 的定义下是合理的。仅初始化约束 在 ECMA-335 Partition I §8.6.1.2 中,可以解释为 String.Empty 的值String后字段不会改变类被初始化。

    关于c# - 更改了 .NET 4.5 中 string.Empty(或 System.String::Empty)的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16618302/

    相关文章:

    C# 与 Express : "This method is reserved for future use" - what does it mean?

    jquery - ASP.NET 请求和 .NET 4.5 - 奇怪的行为

    c# - 在 ASP.NET Web 窗体中管理长时间运行的任务的策略

    c# - 取消backgroundworker操作

    c# - 如何用 where 指定泛型?

    javascript - Jquery Validate - 无法使验证器工作

    c# - 自定义 .net azure 数据工厂事件

    c# - 无法监控安全事件日志

    javascript - 如何在不使用 .aspx 页面的情况下在 JavaScript 中访问 web.config key ?

    c# - 静态 HttpClient 仍在创建 TIME_WAIT tcp 端口