c# .net string compiler-construction bcl

c# - Significado de un comentario confuso sobre “string.Empty” en la fuente.NET/BCL?



compiler-construction (1)

Estoy tratando de entender por qué string.Empty es de readonly y no una const . Vi this Post pero no entiendo el comentario que Microsoft escribió al respecto. Como wrote Jon Skeet en un comentario: "No lo sé, no tiene mucho sentido para mí, para ser honesto ..."

Versión de Common Source Infrastructure 2.0 Release . string.cs está en sscli20 / clr / src / bcl / system / string.cs

// The Empty constant holds the empty string value. //We need to call the String constructor so that the compiler doesn''t mark this as a literal. //Marking this as a literal would mean that it doesn''t show up as a field which we can access //from native. public static readonly String Empty = "";

No puedo ver aquí ninguna llamada de constructor de cadenas y, además, está marcado como literal - ""

¿Puede alguien explicarme en texto sin formato? ¿Qué significa el comentario y por qué es string.Empty readonly y no const ?

Actualizar:
Eric Lippert ha comentado por ahora una respuesta eliminada :

Le pregunté a uno de los veteranos de C # durante el almuerzo acerca de esto y no recordó específicamente por qué se tomó esta decisión, pero supuse que tenía algo que ver con la internación.


La parte importante no es lo que sucede EN esta clase, sino lo que sucede cuando otra clase lo usa (y lo vincula). Déjame explicarte con otro ejemplo:

Supongamos que tiene un Assembly1.dll que contiene una clase que declara

public static const int SOME_ERROR_CODE=0x10; public static readonly int SOME_OTHER_ERROR_CODE=0x20;

y otra clase que consume esto, por ejemplo,

public int TryFoo() { try {foo();} catch (InvalidParameterException) {return SOME_ERROR_CODE;} catch (Exception) { return SOME_OTHER_ERROR_CODE;} return 0x00; }

Compila su clase en Assembly2.dll y lo vincula con Assembly1.dll, como se esperaba, su método devolverá 0x10 en parámetros no válidos, 0x20 en otros errores, 0x00 en caso de éxito.

Especialmente, si crea Assembly3.exe que contiene algo como

int errorcode=TryFoo(); if (errorcode==SOME_ERROR_CODE) bar(); else if (errorcode==SOME_OTHER_ERROR_CODE) baz();

Funcionará como se esperaba (después de haber sido vinculado contra Assembly1.dll y Assembly2.dll)

Ahora, si obtiene una nueva versión de Assembly1.dll, que tiene

public const int SOME_ERROR_CODE=0x11; public readonly int SOME_OTHER_ERROR_CODE=0x21;

Si recompila Assembly3.exe y vincula el último fragmento con el nuevo Assembly1.dll y el Assembly2.dll sin cambios, dejará de funcionar como se esperaba:

bar () NO se llamará correctamente: Assembly2.dll recuerda el LITERAL 0x20, que no es el mismo literal 0x21 que Assembly3.exe lee fuera de Assembly1.dll

baz () se llamará correctamente: Tanto Assembly2.dll como Assembly3.exe se refieren a la REFERENCIA DE SÍMBOLO denominada SOME_OTHER_ERROR_CODE, que en ambos casos se resuelve con la versión actual de Assembly1.dll, por lo que en ambos casos es 0x21.

En resumen: una const crea un LITERAL , una readonly crea una SYMBOL REFERENCE .

LITERALS son internos al marco y no pueden ser ordenados y, por lo tanto, utilizados por el código nativo.

Asi que

public static readonly String Empty = "";

crea una symbol reference (que se resuelve en el momento del primer uso por una llamada al cosntuctor de cadena), que se puede ordenar y usar de forma nativa, mientras que

public static const String Empty = "";

Crearía un literal, que no puede.