Short version:
The C# code
typeof(string).GetField(\"Empty\").SetValue(null, \"Hello world!\");
Console.WriteLine(string.Empty);
The difference lies in the JIT for the new release of .NET, which apparently optimizes references to String.Empty by inlining a reference to a particular String instance rather than load the value stored in the Empty field. This is justified under the definition of the init-only constraint in ECMA-335 Partition I §8.6.1.2, which can be interpreted to mean the value of the String.Empty field will not change after the String class is initialized.