Pregunta ¿Cuál es la diferencia entre const y readonly?


Cuál es la diferencia entre const y readonly y usas uno sobre el otro?


989
2017-09-11 08:02


origen


Respuestas:


Además de la aparente diferencia de

  • tener que declarar el valor en el momento de una definición de const VS readonly los valores se pueden calcular dinámicamente pero deben asignarse antes de que el constructor salga ... después de que se congele.
  • 'const's están implícitamente static. Usas un ClassName.ConstantName notació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;
  }
}

AssemblyB referencias AssemblyA y usa estos valores en el código. Cuando esto se compila,

  • en el caso de const valor, es como un reemplazo de búsqueda, el valor 2 está 'horneado' AssemblyBes IL. Esto significa que si mañana actualizaré I_CONST_VALUE a 20 en el futuro. AssemblyB todavía tendría 2 hasta que recompilarlo.
  • en el caso de readonly valor, es como un ref a una ubicación de memoria. El valor no está cocido en AssemblyBes IL. Esto significa que si la ubicación de la memoria se actualiza, AssemblyB obtiene el nuevo valor sin recompilación Así que si I_RO_VALUE se actualiza a 30, solo necesita construir AssemblyA. Todos los clientes no necesitan ser recompilados.

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

public const int CM_IN_A_METER = 100;

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

public readonly float PI = 3.14;

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


979
2017-09-11 08:24



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


237
2017-09-11 08:15



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 los 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 los valores)
  • Puede ser usado en atributos

Campos de instancia de solo lectura

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

Campos estáticos de solo lectura

  • Se evalúan cuando la ejecución del código llega a la referencia de la clase (cuando se crea una nueva instancia o se ejecuta un método estático)
  • Debe tener un valor evaluado en el momento en que el constructor estático está terminado
  • No se recomienda poner ThreadStaticAttribute en estos (los constructores estáticos se ejecutarán en un único subproceso y establecerán el valor de su subproceso; todos los demás subprocesos tendrán este valor sin inicializar)

125
2017-12-02 11:50



Solo para agregar, ReadOnly para los tipos de referencia solo hace que la referencia sea 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
  }
}

48
2017-09-11 10:37



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

EDITAR: Ver Gishu gotcha arriba por la sutil diferencia


37
2017-09-11 08:04



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.


25
2018-05-21 13:21



Hay una pequeña gotcha con solo lectura. Un campo de solo lectura se puede configurar varias veces dentro del constructor (es). 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
    }
}

20
2017-10-19 22:14



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

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


19
2017-09-11 08:07



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 el const palabra clave y se debe inicializar a medida que se declaran.

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

UN readonly miembro es como una constante en el sentido de que representa un valor inmutable. La diferencia es que readonly El miembro 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 ser declarados como static (están implícitamente estáticos)
  • El valor de la constante se evalúa en tiempo de compilación
  • las constantes se inicializan solo en la declaración

solo lectura

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

19
2017-09-17 11:48



Aquí hay otro enlace demostrando cómo const no es una versión segura o relevante para 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 denota que son estáticos, a diferencia de los campos de solo lectura que sí pueden.
  • Const no puede ser nada excepto los tipos de valor (primitivos)
  • La palabra clave readonly 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 const (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"

14
2018-01-31 11:42



Otra cosa más: los valores de solo lectura se pueden cambiar mediante un código "tortuoso" a través de la reflexión.

var fi = this.GetType()
             .BaseType
             .GetField("_someField", 
                       BindingFlags.Instance | BindingFlags.NonPublic);
fi.SetValue(this, 1);

¿Puedo cambiar un campo heredado de solo lectura privado en C # usando reflection?


8
2017-10-13 02:26