¿Cuál es la diferencia entre const y readonly en C #?


1363

¿Cuál es la diferencia entre consty readonlyen C #?

¿Cuándo usarías uno sobre el otro?


Tuve que buscar varias respuestas para encontrar este enlace, pero es una buena. La toma de Eric Lippert sobre la inmutabilidad en C #
Frank Bryce

2
@donstack, en realidad de acuerdo con la referencia de C # , se puede asignar y reasignar un campo de solo lectura varias veces dentro de la declaración de campo y el constructor.
Marques el

Respuestas:


1289

Aparte de la aparente diferencia de

  • tener que declarar el valor en el momento de la definición de los valores constVS readonlypuede calcularse dinámicamente pero debe asignarse antes de que el constructor salga ... después de eso se congela.
  • 'Const son implícitamente static. Utiliza una ClassName.ConstantNamenotación para acceder a ellos.

Hay una sutil diferencia. Considere una clase definida en AssemblyA.

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly int I_RO_VALUE;
  public Const_V_Readonly()
  {
     I_RO_VALUE = 3;
  }
}

AssemblyBreferencias AssemblyAy utiliza estos valores en el código. Cuando esto se compila,

  • en el caso del constvalor, es como una búsqueda de reemplazo, el valor 2 se "cuece" en la AssemblyBIL. Esto significa que si mañana actualizaré I_CONST_VALUEa 20 en el futuro. AssemblyBtodavía tendría 2 hasta que lo vuelva a compilar .
  • en el caso del readonlyvalor, es como una refubicación de memoria. El valor no está incluido en AssemblyBla IL de. Esto significa que si la ubicación de la memoria se actualiza, AssemblyBobtiene el nuevo valor sin recompilación. Entonces, si I_RO_VALUEse actualiza a 30, solo necesita compilar AssemblyA. No todos los clientes necesitan ser recompilados.

Entonces, si está seguro de que el valor de la constante no cambiará, use a const.

public const int CM_IN_A_METER = 100;

Pero si tiene una constante que puede cambiar (por ejemplo, precisión wrt) ... o en caso de duda, utilice a readonly.

public readonly float PI = 3.14;

Actualización: Aku necesita una mención porque él señaló esto primero. También necesito conectar donde aprendí esto ... C # efectivo - Bill Wagner


77
El staticpunto parece ser el punto más importante y útil -consts are implicitly static
LCJ

28
La parte sobre los valores de referencia es la más importante. Los valores constantes se pueden optimizar.
CodingBarfield

22
readonlyLas variables se pueden cambiar fuera del constructor (reflexión). Es solo el compilador el que intenta impedir que modifiques la var fuera del constructor.
Bitterblue

12
readonlyNo se permite cambiar las variables @ mini-me una vez que el constructor ha finalizado, incluso a través de la reflexión. El tiempo de ejecución pasa a no hacer cumplir esto. El tiempo de ejecución también pasa por no hacer cumplir que no cambia string.Emptya "Hello, world!", pero todavía no afirmaría que esto hace string.Emptymodificable, o que el código no debe suponer que string.Emptysiempre habrá una cadena de longitud cero.

77
blogs.msmvps.com/jonskeet/2014/07/16/… es una lectura interesante solo el costo general de solo lectura
CAD

275

Hay un gotcha con consts! Si hace referencia a una constante de otro conjunto, su valor se compilará directamente en el conjunto de llamada. De esa manera, cuando actualice la constante en el ensamblado al que se hace referencia, ¡no cambiará en el ensamblaje de llamada!


8
En la descompilación (Reflector, ILSpy, ..) una persona NUNCA NUNCA hace referencia a una constante, sin importar el mismo ensamblaje u otro ensamblaje, por lo que no puede analizar el uso de una constante en el código compilado.
springy76

159

Constantes

  • Las constantes son estáticas por defecto
  • Deben tener un valor en tiempo de compilación (puede tener, por ejemplo, 3.14 * 2, pero no puede llamar a métodos)
  • Podría ser declarado dentro de las funciones
  • Se copian en cada ensamblaje que los usa (cada ensamblaje obtiene una copia local de valores)
  • Se puede usar en atributos

Campos de instancia de solo lectura

  • Debe tener un valor establecido, para cuando salga el constructor
  • Se evalúan cuando se crea la instancia

Campos de solo lectura estática

  • Se evalúan cuando la ejecución del código alcanza la referencia de clase (cuando se crea una nueva instancia o se ejecuta un método estático)
  • Debe tener un valor evaluado para cuando el constructor estático termine
  • No se recomienda poner ThreadStaticAttribute en estos (los constructores estáticos se ejecutarán en un solo hilo y establecerán el valor para su hilo; todos los otros hilos tendrán este valor sin inicializar)

58

Solo para agregar, ReadOnly para tipos de referencia solo hace que la referencia sea de solo lectura, no los valores. Por ejemplo:

public class Const_V_Readonly
{
  public const int I_CONST_VALUE = 2;
  public readonly char[] I_RO_VALUE = new Char[]{'a', 'b', 'c'};

  public UpdateReadonly()
  {
     I_RO_VALUE[0] = 'V'; //perfectly legal and will update the value
     I_RO_VALUE = new char[]{'V'}; //will cause compiler error
  }
}

¿Hay algún otro tipo de referencia stringque pueda usar como constante?
springy76

Puede tener consttipos de referencia que no sean cadena, pero la constante solo puede tener el valor null.
Mike Rosoft

40

Esto lo explica . Resumen: const se debe inicializar en el momento de la declaración, solo se puede inicializar en el constructor (y, por lo tanto, tener un valor diferente según el constructor utilizado).

EDITAR: Vea el gotcha de Gishu arriba para la sutil diferencia


32

const: No se puede cambiar en ningún lado.

readonly: Este valor solo se puede cambiar en el constructor. No se puede cambiar en las funciones normales.


26

Hay un pequeño gotcha con solo lectura. Un campo de solo lectura se puede establecer varias veces dentro de los constructores. Incluso si el valor se establece en dos constructores encadenados diferentes, todavía está permitido.


public class Sample {
    private readonly string ro;

    public Sample() {
        ro = "set";
    }

    public Sample(string value) : this() {
        ro = value; // this works even though it was set in the no-arg ctor
    }
}

26

Un miembro constante se define en tiempo de compilación y no se puede cambiar en tiempo de ejecución. Las constantes se declaran como un campo, utilizando la constpalabra clave y deben inicializarse a medida que se declaran.

public class MyClass
{
    public const double PI1 = 3.14159;
}

Un readonlymiembro es como una constante en el sentido de que representa un valor inmutable. La diferencia es que un readonlymiembro se puede inicializar en tiempo de ejecución, en un constructor, y también se puede inicializar a medida que se declaran.

public class MyClass1
{
     public readonly double PI2 = 3.14159;

     //or

     public readonly double PI3;

     public MyClass2()
     {
         PI3 = 3.14159;
     }
}

const

  • No pueden declararse como static(son implícitamente estáticos)
  • El valor de constante se evalúa en tiempo de compilación
  • las constantes se inicializan solo en la declaración

solo lectura

  • Pueden ser de nivel de instancia o estáticos.
  • El valor se evalúa en tiempo de ejecución.
  • readonly puede inicializarse en declaración o por código en el constructor

66
No pueden ser estáticos , son estáticos. Debe dejar en claro si quiere decir que uno no puede declararstatic const int i = 0;
nawfal

¿Puede explicar por qué constno se pueden hacer declaraciones dentro de los métodos?
Minh Tran

21

Una constante es una constante de tiempo de compilación, mientras que solo lectura permite calcular un valor en tiempo de ejecución y establecerlo en el constructor o inicializador de campo. Por lo tanto, una 'constante' siempre es constante, pero 'solo lectura' es de solo lectura una vez que se asigna.

Eric Lippert, del equipo de C #, tiene más información sobre los diferentes tipos de inmutabilidad.


15

Aquí hay otro enlace que demuestra cómo const no es segura para la versión o relevante para los tipos de referencia.

Resumen :

  • El valor de su propiedad const se establece en tiempo de compilación y no puede cambiar en tiempo de ejecución
  • Const no se puede marcar como estático: la palabra clave indica que son estáticos, a diferencia de los campos de solo lectura que sí.
  • Const no puede ser nada excepto tipos de valor (primitivo)
  • La palabra clave de solo lectura marca el campo como inmutable. Sin embargo, la propiedad se puede cambiar dentro del constructor de la clase.
  • La palabra clave de solo lectura también se puede combinar con estática para que actúe de la misma manera que una constante (al menos en la superficie). Hay una marcada diferencia cuando miras el IL entre los dos
  • los campos const están marcados como "literales" en IL, mientras que readonly es "initonly"

11

Solo lectura : el valor se puede cambiar a través de Ctor en tiempo de ejecución. Pero no a través de la función miembro

Constante : por defecto estático. El valor no se puede cambiar desde ningún lugar (Ctor, Función, tiempo de ejecución, etc.)


gracias por no hacerme leer 4 párrafos solo por estas dos conclusiones ...
Don Cheadle


6

Creo que un constvalor es el mismo para todos los objetos (y debe inicializarse con una expresión literal), mientras que readonlypuede ser diferente para cada instanciación ...


5

Uno de los miembros del equipo en nuestra oficina proporcionó la siguiente guía sobre cuándo usar const, static y readonly:

  • Use const cuando tenga una variable de un tipo que pueda conocer en tiempo de ejecución (literal de cadena, int, double, enums, ...) que desea que todas las instancias o consumidores de una clase tengan acceso a donde el valor no debería cambiar.
  • Use static cuando tenga datos de que desea que todas las instancias o consumidores de una clase tengan acceso a donde el valor puede cambiar.
  • Use estática de solo lectura cuando tenga una variable de un tipo que no puede saber en tiempo de ejecución (objetos) que desea que todas las instancias o consumidores de una clase tengan acceso a donde el valor no debería cambiar.
  • Use readonly cuando tenga una variable de nivel de instancia que sabrá en el momento de la creación del objeto que no debería cambiar.

Una nota final: un campo constante es estático, pero lo inverso no es cierto.


1
Creo que te refieres a "conversar". Lo inverso sería "un campo no constante no es estático". Lo que puede o no ser cierto. Lo contrario, "un campo estático es (siempre) constante" no es cierto.
Michael Blackburn

5

Ambos son constantes, pero también hay una constante disponible en tiempo de compilación. Esto significa que un aspecto de la diferencia es que puede usar variables constantes como entrada para construir constructores de atributos, pero no solo variables de lectura.

Ejemplo:

public static class Text {
  public const string ConstDescription = "This can be used.";
  public readonly static string ReadonlyDescription = "Cannot be used.";
}

public class Foo 
{
  [Description(Text.ConstDescription)]
  public int BarThatBuilds {
    { get; set; }
  }

  [Description(Text.ReadOnlyDescription)]
  public int BarThatDoesNotBuild {
    { get; set; }
  }
}

5
  • cuando usar constoreadonly

    • const

      • constante de tiempo de compilación : constante absoluta , el valor se establece durante la declaración, está en el propio código IL
    • readonly

      • constante de tiempo de ejecución : se puede establecer en el constructor / init a través del archivo de configuración, es decir App.config, pero una vez que se inicializa no se puede cambiar

4

Las variables marcadas const son poco más que macros #definidas fuertemente tipadas, en tiempo de compilación las referencias de variables const se reemplazan con valores literales en línea. Como consecuencia, solo ciertos tipos de valores primitivos incorporados pueden usarse de esta manera. Las variables marcadas como solo lectura se pueden establecer, en un constructor, en tiempo de ejecución y su solo lectura se aplica también durante el tiempo de ejecución. Hay un costo de rendimiento menor asociado con esto, pero significa que puede usar solo lectura con cualquier tipo (incluso tipos de referencia).

Además, las variables const son inherentemente estáticas, mientras que las variables de solo lectura pueden ser específicas de la instancia si se desea.


Se agregó que los consts son macros #define fuertemente tipados . De lo contrario, podemos ahuyentar a todas las personas C o C ++. :-)
Jason Baker

4

CONST

  1. La palabra clave const se puede aplicar a campos o variables locales
  2. Debemos asignar campo constante al momento de la declaración
  3. No hay memoria asignada porque el valor constante está incrustado en el propio código IL después de la compilación. Es como encontrar todas las ocurrencias de la variable constante y reemplazar por su valor. Entonces, el código IL después de la compilación tendrá valores codificados en lugar de variables constantes
  4. Const en C # son estáticos por defecto.
  5. El valor es constante para todos los objetos.
  6. Hay un problema de versiones de dll: esto significa que cada vez que cambiamos una variable o propiedad const pública, (de hecho, no se supone que se cambie teóricamente), cualquier otra dll o ensamblado que use esta variable debe reconstruirse
  7. Solo los tipos integrados de C # pueden declararse como constantes
  8. El campo Const no se puede pasar como parámetro ref o out

Solo lectura

  1. la palabra clave de solo lectura se aplica solo a los campos, no a las variables locales
  2. Podemos asignar un campo de solo lectura en el momento de la declaración o en el constructor, no en ningún otro método.
  3. memoria dinámica asignada para campos de solo lectura y podemos obtener el valor en tiempo de ejecución.
  4. Readonly pertenece al objeto creado, por lo que se accede a través de una sola instancia de clase. Para que sea miembro de clase, debemos agregar una palabra clave estática antes de solo lectura.
  5. El valor puede ser diferente dependiendo del constructor utilizado (ya que pertenece al objeto de la clase)
  6. Si declara un tipo no primitivo (tipo de referencia) como solo lectura, solo la referencia es inmutable, no el objeto que contiene.
  7. Dado que el valor se obtiene en tiempo de ejecución, no hay ningún problema de versiones de DLL con campos / propiedades de solo lectura.
  8. Podemos pasar el campo de solo lectura como parámetros ref o out en el contexto del constructor.

3

Otro gotcha .

Dado que const realmente solo funciona con tipos de datos básicos, si desea trabajar con una clase, puede sentirse "obligado" a usar ReadOnly. Sin embargo, ¡cuidado con la trampa! ReadOnly significa que no puede reemplazar el objeto con otro objeto (no puede hacer que se refiera a otro objeto). ¡Pero cualquier proceso que tenga una referencia al objeto es libre de modificar los valores dentro del objeto!

Así que no se confunda al pensar que ReadOnly implica que un usuario no puede cambiar las cosas. No hay una sintaxis simple en C # para evitar que una instancia de una clase cambie sus valores internos (que yo sepa).


Sí, ese es más un tema general. Si tiene una propiedad get only que expone una lista de arrays, aún puede modificarla. No puede establecer una lista de arrays diferente para esa propiedad, pero no puede evitar que el usuario modifique la lista de arrays.
Gishu

3

A consttiene que estar codificado , donde readonlyse puede establecer en el constructor de la clase.


3

Hay una diferencia notable entre los campos const y readonly en C # .Net

const es estático por defecto y debe inicializarse con un valor constante, que no puede modificarse más adelante. El cambio de valor tampoco está permitido en los constructores. No se puede usar con todos los tipos de datos. Por ejemplo, DateTime. No se puede usar con el tipo de datos DateTime.

public const DateTime dt = DateTime.Today;  //throws compilation error
public const string Name = string.Empty;    //throws compilation error
public readonly string Name = string.Empty; //No error, legal

readonly puede declararse como estático, pero no es necesario. No es necesario inicializar en el momento de la declaración. Su valor se puede asignar o cambiar usando el constructor. Por lo tanto, da ventaja cuando se usa como miembro de clase de instancia. Dos instancias diferentes pueden tener un valor diferente de campo de solo lectura. Por ex -

class A
{
    public readonly int Id;

    public A(int i)
    {
        Id = i;
    }
}

Luego, el campo de solo lectura se puede inicializar con valores específicos instantáneos, de la siguiente manera:

A objOne = new A(5);
A objTwo = new A(10);

Aquí, instancia objOne tendrá el valor del campo de solo lectura como 5 y objTwo tiene 10. Lo que no es posible con const.


2

Una constante se compilará en el consumidor como un valor literal, mientras que la cadena estática servirá como referencia al valor definido.

Como ejercicio, intente crear una biblioteca externa y consumirla en una aplicación de consola, luego modifique los valores en la biblioteca y vuelva a compilarla (sin recompilar el programa del consumidor), suelte la DLL en el directorio y ejecute el EXE manualmente, debería encontrar que la cadena constante no cambia.


Dudo sinceramente que sea verdad ... Iré a comprobarlo.
ljs

esta es una de las 50 formas específicas para mejorar su C # - amazon.co.uk/Effective-Specific-Ways-Improve-Your/dp/0321245660/...
Russ Cam


@ Andrew Hare: sí, acabo de comprobarlo. Estoy muy sorprendido, eso es un verdadero problema, estoy realmente muy sorprendido por eso, ¡asombrado de que sea el caso ...!
ljs

Sin embargo, me opongo al uso de la palabra puntero aquí. No es un puntero, que es una referencia, y no es una diferencia en C # como se puede manipular punteros no administrados en modo no seguro por lo que es importante distinguir entre los dos.
ljs

2

Constante

Necesitamos proporcionar el valor al campo constante cuando se define. El compilador guarda el valor de la constante en los metadatos del ensamblado. Esto significa que una constante solo se puede definir para el tipo primitivo como boolean, char, byte, etc. Las constantes siempre se consideran miembros estáticos, no miembros de instancia.

Solo lectura

Los campos de solo lectura solo se pueden resolver en tiempo de ejecución. Eso significa que podemos definir un valor para un valor utilizando el constructor para el tipo en el que se declara el campo. El compilador realiza la verificación de que los campos de solo lectura no están escritos por ningún otro método que no sea el constructor.

Más sobre ambos explicados aquí en este artículo


1

Principalmente; puede asignar un valor a un campo de solo lectura estático a un valor no constante en tiempo de ejecución, mientras que a const se le debe asignar un valor constante.


1

Const y readonly son similares, pero no son exactamente lo mismo. Un campo constante es una constante en tiempo de compilación, lo que significa que ese valor puede calcularse en tiempo de compilación. Un campo de solo lectura habilita escenarios adicionales en los que se debe ejecutar algún código durante la construcción del tipo. Después de la construcción, un campo de solo lectura no se puede cambiar.

Por ejemplo, los miembros const se pueden usar para definir miembros como:

struct Test
{
    public const double Pi = 3.14;
    public const int Zero = 0;
}

ya que valores como 3.14 y 0 son constantes de tiempo de compilación. Sin embargo, considere el caso en el que define un tipo y desea proporcionar algunas instancias prefabricadas del mismo. Por ejemplo, es posible que desee definir una clase de Color y proporcionar "constantes" para colores comunes como Negro, Blanco, etc. No es posible hacer esto con miembros constantes, ya que los lados derechos no son constantes de tiempo de compilación. Se podría hacer esto con miembros estáticos regulares:

public class Color
{
    public static Color Black = new Color(0, 0, 0);
    public static Color White = new Color(255, 255, 255);
    public static Color Red = new Color(255, 0, 0);
    public static Color Green = new Color(0, 255, 0);
    public static Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

pero entonces no hay nada para evitar que un cliente de Color se meta con él, tal vez intercambiando los valores de Blanco y Negro. No hace falta decir que esto causaría consternación a otros clientes de la clase Color. La función "solo lectura" aborda este escenario. Simplemente introduciendo la palabra clave de solo lectura en las declaraciones, preservamos la inicialización flexible al tiempo que evitamos que el código del cliente se pierda.

public class Color
{
    public static readonly Color Black = new Color(0, 0, 0);
    public static readonly Color White = new Color(255, 255, 255);
    public static readonly Color Red = new Color(255, 0, 0);
    public static readonly Color Green = new Color(0, 255, 0);
    public static readonly Color Blue = new Color(0, 0, 255);
    private byte red, green, blue;

    public Color(byte r, byte g, byte b) {
        red = r;
        green = g;
        blue = b;
    }
}

Es interesante observar que los miembros const son siempre estáticos, mientras que un miembro de solo lectura puede ser estático o no, al igual que un campo normal.

Es posible utilizar una sola palabra clave para estos dos propósitos, pero esto conduce a problemas de versiones o problemas de rendimiento. Supongamos por un momento que usamos una sola palabra clave para esto (const) y un desarrollador escribió:

public class A
{
    public static const C = 0;
}

y un desarrollador diferente escribió un código que dependía de A:

public class B
{
    static void Main() {
        Console.WriteLine(A.C);
    }
}

Ahora, ¿puede el código generado depender del hecho de que AC es una constante de tiempo de compilación? Es decir, ¿puede el uso de AC simplemente ser reemplazado por el valor 0? Si dice "sí" a esto, entonces eso significa que el desarrollador de A no puede cambiar la forma en que se inicializa AC; esto ata las manos del desarrollador de A sin permiso. Si responde "no" a esta pregunta, se pierde una optimización importante. Quizás el autor de A está seguro de que AC siempre será cero. El uso de const y readonly permite al desarrollador de A especificar la intención. Esto permite un mejor comportamiento de versiones y también un mejor rendimiento.


1

ReadOnly: el valor se inicializará solo una vez desde el constructor de la clase.
const: se puede inicializar en cualquier función pero solo una vez


1

La diferencia es que el valor de un campo de solo lectura estático se establece en tiempo de ejecución, por lo que puede tener un valor diferente para diferentes ejecuciones del programa. Sin embargo, el valor de un campo constante se establece en una constante de tiempo de compilación.

Recuerde: para los tipos de referencia, en ambos casos (estático e instancia), el modificador de solo lectura solo le impide asignar una nueva referencia al campo. Específicamente no hace inmutable el objeto señalado por la referencia.

Para obtener más información, consulte las preguntas frecuentes de C # sobre este tema: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx


1

Las variables constantes se declaran e inicializan en tiempo de compilación. El valor no se puede cambiar después de las salas. Las variables de solo lectura se inicializarán solo desde el constructor estático de la clase. Solo lectura se usa solo cuando queremos asignar el valor en tiempo de ejecución.


1

Const : valor constante absoluto durante el tiempo de vida de la aplicación.

Solo lectura : se puede cambiar en tiempo de ejecución.


1
Su definición de 'Solo lectura' que puede cambiar es errónea. Supongo que por 'cambio' querías decir 'establecer', como 'se puede establecer en tiempo de ejecución'.
Ahmed

0

Una cosa para agregar a lo que la gente ha dicho anteriormente. Si tiene un ensamblado que contiene un valor de solo lectura (por ejemplo, solo lectura MaxFooCount = 4;), puede cambiar el valor que ven los ensamblados que llaman al enviar una nueva versión de ese ensamblaje con un valor diferente (por ejemplo, solo lectura MaxFooCount = 5;)

Pero con una constante, se plegaría en el código de la persona que llama cuando se compila la persona que llama.

Si ha alcanzado este nivel de competencia en C #, está listo para el libro de Bill Wagner, C # efectivo: 50 formas específicas de mejorar su C # que responde a esta pregunta en detalle (y otras 49 cosas más).

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.