关于c#:更改了.NET 4.5中string.empty(或system.string::empty)的行为

Changed behavior of string.Empty (or System.String::Empty) in .NET 4.5

短版:

# C代码

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

当编译和运行,使输出"Hello world!"在.NET 4.0版和更早的,但给""在.NET 4.5 4.5.1和.NET。

如何写这样的一场被忽略,或复位,世卫组织这场?

时间版本:

我从来没有真正理解为什么《string.Empty场(又称为[mscorlib]System.String::Empty)是不const(又名。literal湖),"为什么不是空字符串常数。A?"这意味着,例如,我们可以在"T C # string.Empty在以下情况使用:

  • 在一switch语句的case string.Empty:
  • 作为可选参数的默认值在void M(string x = string.Empty) { },样
  • 工人们样的属性,[SomeAttribute(string.Empty)]
  • 其他的情况下,在编译的时间常数是必需的

它已经影响到我们的宗教是"是否被使用过或""string.Empty湖",# C,我要使用字符串或空或空字符串。。。。。。。。""初始化字符串?"。。。。。。。

几年前,一个由Emptyi安德烈自己设置一些其他的字符串或通过反射,和湖多少部件的Bcl behaving strangely开始因为它。这是相当多的。参考和变化的Empty滑稽的坚持完整的生命的应用。现在,我想那天那个小特技重复序列,然后用.NET 4.5机器,我不能这样做了。

(NB!如果你有在你的.NET 4.5 PowerShell安静的机器,可能是使用旧版本的.NET,以尝试复制到pasting [String].GetField("Empty").SetValue($null,"Hello world!")PowerShell的一些影响,这一变化的参考湖)。

当我试图搜索这一原因,我坐在线程"的兴趣是什么,因为这fatalexecutionengineerror。4.5测试版?"在公认的答案。这是它的两个通孔,这是System.String4.0版本,有一个静态构造函数.cctor其中场Empty什么集(C #源,这会是一场很及时的初始化时,当然),而在静态构造函数4.5 NO的存在。在两个版本,它看起来是一样的:场

1
.field public static initonly string Empty

作为一个dasm湖IL)。

没有其他的场String::Empty似乎比的影响。作为一个例子,一个System.Diagnostics.Debugger::DefaultCategoryexperimented。这是类似案例:a密封舱(含static readonlystatic initonly)string场型。但在这个案例它精细改变值(参考)通过反射。

回到这个问题:

技术上的知识,这是可能的,Empty似乎没有变化(4.5)设置在一场吗?我已经给了# C编译器不读"作弊"的酒店,它的输出细胞样:

1
ldsfld     string [mscorlib]System.String::Empty

因此,实际的场应该读取。

编辑后的赏金是我的问题:注意上的写操作(当然这需要反思的是,从一场readonly(又名initonly在IL))是为喜欢的作品。它是anomalous是读取操作。如果你读与反思,在typeof(string).GetField("Empty").GetValue(null)(IU,一切是正常的价值是变化的湖泊)。评论下面的湖。

因此,更好的问题是:为什么这个新版本的框架,特别是当它读这场作弊?


区别在于.NET新版本的JIT,它显然通过引入对特定String实例的引用而不是加载存储在Empty字段中的值来优化对String.Empty的引用。根据ECMA-335第I部分第8.6.1.2节中仅init约束的定义,这是合理的,可以解释为在初始化String类后,String.Empty字段的值不会改变。


我没有答案,只是暗示一下。

我在String::EmptySystem.Diagnostics.Debugger::DefaultCategory之间看到的唯一区别是,第一个标记为__DynamicallyInvokableAttribute

我不知道这个未记录的属性的含义。关于这个属性的一个问题已经被问到了:什么是"dynamicallyInvokable"属性?

我只能假设这个属性被运行时捕获以进行缓存?


因为它可以。

这些系统定义的initonly字段的值是.NET运行时的全局不变量。如果这些不变量被破坏,就不再有任何关于行为的保证。

在C++中,我们可能会有一个规则将此指定为未定义的行为。在.NET中,它也是未定义的行为,仅仅是因为没有任何规则说明当System.String.Empty.Length > 0时会发生什么。.net和c的所有层的整个规范描述了当System.String.Empty.Length == 0和一大堆不变量也成立时的行为。

有关运行时和含义之间不同的优化的详细信息,请参阅

  • 要求反射API覆盖System.String.Empty会有什么影响?