¿Por qué no es String.Empty una constante?


189

En .Net, ¿por qué String.Empty es de solo lectura en lugar de una constante? Me pregunto si alguien sabe cuál fue el razonamiento detrás de esa decisión.


55
Esta pregunta puede resolver esta, la breve respuesta es que nadie lo sabe ...
gdoron está apoyando a Monica el

Sí, +1 por la respuesta de Eric Lippert, ¡gracias!
travis

Particularmente dado que Decimal.Zero es constante (desde la perspectiva del usuario que es ...)
Hamish Grubijan

Respuestas:


149

La razón que static readonlyse usa en lugar de constse debe al uso con código no administrado, como lo indica Microsoft aquí en la versión Shared Source Common Language Infrastructure 2.0 . El archivo a mirar es sscli20\clr\src\bcl\system\string.cs.

La constante vacía contiene el valor de cadena vacía. Necesitamos llamar al constructor de cadenas para que el compilador no marque esto como un literal.

Marcar esto como literal significaría que no aparece como un campo al que podemos acceder desde nativo.

Encontré esta información de este útil artículo en CodeProject .


Realmente agradecería si pudiera explicar este comentario (porque Jon Skeet no pudo ...) ver aquí: stackoverflow.com/questions/8462697/…
gdoron está apoyando a Monica el

2
@ gdoron: Mi suposición (y es una suposición) es esta. Cuando un valor se define como un literal (una constante), su valor se inserta en los lugares donde se hace referencia, mientras que cuando no se define como literal, se hace referencia a la fuente del valor y se recupera el valor real en tiempo de ejecución. Sospecho que esto último puede garantizar que se produzca la clasificación adecuada de la cadena entre nativo y .NET en tiempo de ejecución; si fuera literal, tal vez el compilador nativo necesitaría de alguna manera extraer el valor literal en su código nativo, lo que probablemente no sea factible. Sin embargo, todo esto es una conjetura de mi parte.
Jeff Yates

77
Significa que uno tiene que usar "", en lugar de string. Vacío para los valores de parámetros predeterminados en los métodos. Lo cual es un poco molesto.
nicodemus13

17
"" puede parecer un error, mientras cadena. Vacío muestra intención deliberada
Christopher Stevenson

3
@JeffYates Agregaría que el hecho de que no sea consistente ya es molesto. La gente vería el resto del código y se preguntaría "¿por qué está usando" "aquí en lugar de String.Empty?". Estoy considerando seriamente no usar String.Emptymás solo por esa razón.
julealgon

24

Creo que hay mucha confusión y malas respuestas aquí.

En primer lugar, los constcampos son staticmiembros ( no miembros de instancia ).

Consulte la sección 10.4 Constantes de la especificación del lenguaje C #.

Aunque las constantes se consideran miembros estáticos, una declaración constante no requiere ni permite un modificador estático.

Si los public constmiembros son estáticos, uno no podría considerar que una constante creará un nuevo Objeto.

Dado esto, las siguientes líneas de código hacen exactamente lo mismo con respecto a la creación de un nuevo Objeto.

public static readonly string Empty = "";
public const string Empty = "";

Aquí hay una nota de Microsoft que explica la diferencia entre los 2:

La palabra clave de solo lectura es diferente de la palabra clave const. Un campo constante solo puede inicializarse en la declaración del campo. Un campo de solo lectura se puede inicializar en la declaración o en un constructor. Por lo tanto, los campos de solo lectura pueden tener valores diferentes según el constructor utilizado. Además, si bien un campo constante es una constante de tiempo de compilación, el campo de solo lectura se puede usar para constantes de tiempo de ejecución, ...

Entonces encuentro que la única respuesta plausible aquí es la de Jeff Yates.


+1 para las palabras amables y aclaraciones con respecto a la especificación de C # en const y static readonly.
Jeff Yates

17
Al releer esto, no estoy de acuerdo con eso const stringy static readonly stringhago lo mismo. Los valores constantes se sustituyen en el código vinculado, mientras que los valores de solo lectura estática están referenciados. Si tiene una constbiblioteca A que utiliza la biblioteca B, la biblioteca B reemplazará todas las referencias a esa constvariable con su valor literal; si esa variable fuera en su static readonlylugar, sería referenciada y su valor determinado en tiempo de ejecución.
Jeff Yates

3
El punto de Jeff es importante cuando se hace referencia a bibliotecas. Si recompila A y lo redistribuye, sin recompilar B , B seguirá utilizando los valores anteriores.
Mark Sowul

5
String.Empty read only instead of a constant?

Si hace que una cadena sea constante , el compilador se reemplaza con la cadena real en todas partes donde la llame y completa su código con la misma cadena por todas partes y cuando se ejecuta el código también es necesario leer una y otra vez esa cadena de la memoria diferente datos.

Si deja su cadena de lectura solo en un lugar como es String.Empty, el programa mantiene la misma cadena solo en un lugar y la lee, o se refiere a ella, manteniendo los datos en la memoria como mínimo.

Además, si compila cualquier dll utilizando String.Empty como constante y, por cualquier motivo, el cambio de String.Empty, el dll compilado ya no funcionará de la misma manera, ya que crea costel código interno para mantener una copia de la cadena en cada llamada

Vea este código por ejemplo:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

vendrá por el compilador como:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

y la convocatoria de la asamblea

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Editar: error tipográfico corregido


Entonces, ¿esto significa que la cadena const siempre debe ser instanciada con la clase que contiene esa const? Parece que es mucho mejor usar solo lectura estática entonces.
el berserker

@theberserker bien es mejor, pero tienes todas las opciones para usar.
Aristos

> entonces el dll compilado ya no funcionará igual, porque el costo hace que el código interno conserve una copia de la cadena en cada llamada. @Aristos Eso no está del todo bien. Una vez que se compila el código, se hará referencia a la "copia" de la cadena en el bloque TEXT del ejecutable, y todo el código solo hará referencia al mismo bloque de memoria. Lo que citó en su segundo paso es simplemente un paso intermedio.
Peter Dolkens el

@ user1533523 gracias por la nota - Haré una prueba cuando encuentre algo de tiempo para revisar esto
Aristos

¿Cómo obtuviste ese código de ensamblaje? ¡C # no se compila para ensamblar!
jv110

0

Esta respuesta existe para fines históricos.

Originalmente:

Porque Stringes una clase y por lo tanto no puede ser una constante.

Discusión extendida:

Una gran cantidad de diálogos útiles fueron elaborados al examinar esta respuesta, y en lugar de eliminarla, este contenido se reproduce directamente:

En .NET, (a diferencia de Java) string y String son exactamente lo mismo. Y sí, puede tener constantes literales de cadena en .NET - DrJokepu 03 de febrero de 2009 a las 16:57

¿Estás diciendo que una clase no puede tener constantes? - StingyJack 03 de febrero de 2009 a las 16:58

Sí, los objetos tienen que usar solo lectura. Solo las estructuras pueden hacer constantes. Creo que cuando usa en stringlugar del Stringcompilador, cambia la constante en un solo lectura para usted. Todo tiene que ver con mantener contentos a los programadores de C. - Garry Shutler el 3 de febrero de 2009 a las 16:59

tvanfosson acaba de explicarlo un poco más detallado. "X no puede ser una constante, porque el Y que contiene es una clase" fue un poco demasiado libre de contexto;) - Leonidas 03 de febrero de 2009 a las 17:01

string.Empty es una propiedad estática que devuelve una instancia de la clase String, es decir, la cadena vacía, no la clase de cadena en sí. - tvanfosson 03 de febrero de 2009 a las 17:01

Empty es una instancia de solo lectura (no es una propiedad) de la clase String. - senfo 3 de febrero de 2009 a las 17:02

Herida en la cabeza. Sigo pensando que tengo razón, pero ahora estoy menos seguro. ¡Se requiere investigación esta noche! - Garry Shutler 3 de febrero de 2009 a las 17:07

La cadena vacía es una instancia de la clase de cadena. Vacío es un campo estático (no es una propiedad, estoy corregido) en la clase String. Básicamente, la diferencia entre un puntero y lo que señala. Si no fuera de solo lectura, podríamos cambiar a qué instancia se refiere el campo Vacío. - tvanfosson 03 de febrero de 2009 a las 17:07

Garry, no necesitas hacer ninguna investigación. Piénsalo. La cadena es una clase. Vacío es una instancia de una cadena. - senfo 3 de febrero de 2009 a las 17:12

Hay algo que no entiendo: ¿cómo puede el constructor estático de la clase String crear una instancia de la clase String? ¿No es una especie de escenario de "la gallina o el huevo"? - DrJokepu 03 de febrero de 2009 a las 17:12 5

Esta respuesta sería correcta para casi cualquier otra clase que no sea System.String. .NET realiza una gran cantidad de funciones especiales para cadenas, y una de ellas es que PUEDES tener constantes de cadena, solo pruébalo. En este caso, Jeff Yates tiene la respuesta correcta. - Joel Mueller 03 de febrero de 2009 a las 19:25

Como se describe en §7.18, una expresión constante es una expresión que puede evaluarse completamente en tiempo de compilación. Dado que la única forma de crear un valor no nulo de un tipo de referencia que no sea una cadena es aplicar el nuevo operador, y dado que el nuevo operador no está permitido en una expresión constante, el único valor posible para constantes de tipos de referencia que no sea string es nulo. Los dos comentarios anteriores fueron tomados directamente de la especificación del lenguaje C # y reiteran lo que mencionó Joel Mueller. - senfo 4 de febrero de 2009 a las 15:05 5


Por favor, vote hacia abajo la respuesta correcta. Si pasa a Definición, encontrará que está en la clase String y es una instancia de String. El hecho de que se muestre en minúsculas es la magia del compilador.
Garry Shutler

No fui yo quien te rechazó, sino que en .NET, (a diferencia de Java), string y String son exactamente lo mismo. Y sí, puede tener constantes literales de cadena en .NET
Tamas Czinege 03 de

10
Esta respuesta sería correcta para casi cualquier otra clase que no sea System.String. .NET realiza una gran cantidad de funciones especiales para cadenas, y una de ellas es que PUEDES tener constantes de cadena, solo pruébalo. En este caso, Jeff Yates tiene la respuesta correcta.
Joel Mueller

77
Casi borré esta respuesta porque apareció una mucho mejor, pero vale la pena mantener la discusión en estos comentarios.
Garry Shutler

1
@Garry, tienes suerte de que leí tu último comentario, de lo contrario también votaría negativamente. Una cadena tiene una característica especial en .NET, que si es una clase de referencia, puede ser una constante.
Shimmy Weitzhandler
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.