Comportamiento modificado de string.Empty (o System.String :: Empty) en .NET 4.5

Version corta:

El código C #

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

Cuando se compila y ejecuta, da salida."Hello world!" bajo .NET versión 4.0 y anteriores, pero da"" bajo .NET 4.5 y .NET 4.5.1.

¿Cómo se puede ignorar una escritura en un campo de esa manera o, quién reinicia este campo?

Versión más larga:

Nunca he entendido realmente por qué elstring.Empty campo (también conocido como[mscorlib]System.String::Empty) no esconst (aliasliteral), ver "¿Por qué no es String.Empty una constante?". Esto significa que, por ejemplo, en C # no podemos usarstring.Empty en las siguientes situaciones:

en unswitch declaración en el formulariocase string.Empty:Como el valor predeterminado de un parámetro opcional, comovoid M(string x = string.Empty) { }Al aplicar un atributo, como[SomeAttribute(string.Empty)]Otras situaciones donde se requiere una constante de tiempo de compilación

que tiene implicaciones para la conocida "guerra religiosa" sobre si usar o nostring.Empty o"", ver "En C #, ¿debería usar string.Empty o String.Empty o "" para inicializar una cadena?".

Hace un par de años me entretuve con la ambientación.Empty a otra instancia de cadena a través de la reflexión, y ver cuántas partes del BCL comenzaron a comportarse de manera extraña debido a esto. Eran muchos. Y el cambio de laEmpty La referencia pareció persistir durante toda la vida de la aplicación. Ahora, el otro día intenté repetir ese pequeño truco, pero luego usé una máquina .NET 4.5 y ya no pude hacerlo.

(¡NOTA! Si tiene .NET 4.5 en su máquina, probablemente suPowerShell Todavía usa una versión anterior de .NET, así que intente copiar y pegar[String].GetField("Empty").SetValue($null, "Hello world!") en PowerShell para ver algunos efectos de cambiar esta referencia.)

Cuando traté de buscar una razón para esto, me topé con el interesante hilo "¿Cuál es la causa de este FatalExecutionEngineError en .NET 4.5 beta?". En la respuesta aceptada a esa pregunta, se observa que a través de la versión 4.0,System.String tenía un constructor estático.cctor en el cual el campoEmpty se estableció (en la fuente de C #, que probablemente solo sería un inicializador de campo, por supuesto), mientras que en 4.5 no existe ningún constructor estático. En ambas versiones, el campo en sí se ve igual:

.field public static initonly string Empty

(como se ve con IL DASM).

No hay otros campos queString::Empty Parece estar afectado. Como ejemplo, experimenté conSystem.Diagnostics.Debugger::DefaultCategory. Este caso parece análogo: una clase sellada que contiene unstatic readonly (static initonly) campo de tipostring. Pero en este caso funciona bien cambiar el valor (referencia) a través de la reflexión.

De vuelta a la pregunta:

¿Cómo es posible, técnicamente, que?Empty no parece cambiar (en 4.5) cuando configuro el campo? He verificado que el compilador de C # no "hace trampa" con la lectura, da salida a IL como:

ldsfld     string [mscorlib]System.String::Empty

por lo que el campo real debe ser leído.

Editar después de la recompensa se puso en mi pregunta: Tenga en cuenta que la operación de escritura (que necesita una reflexión segura, ya que el campo esreadonly (a.k.a.initonly en la IL)) en realidad funciona como se espera. Es elleer Operación que es anómala. Si lees con reflexión, como entypeof(string).GetField("Empty").GetValue(null), todo es normal (es decir, se ve el cambio de valor). Ver comentarios a continuación.

Entonces, la mejor pregunta es: ¿Por qué esta nueva versión de la infraestructura hace trampa cuando lee este campo en particular?

Respuestas a la pregunta(3)

Su respuesta a la pregunta