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

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

Además de la aparente diferencia de

  • tener que declarar el valor en el momento de una definición para un const valores de readonly VS pueden calcularse dinámicamente pero deben asignarse antes de que el constructor salga … después de que se congele.
  • ‘const’s son implícitamente static . Utiliza una notación ClassName.ConstantName 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 referencia a AssemblyA y utiliza estos valores en el código. Cuando esto se comstack,

  • en el caso del valor de const , es como un reemplazo de búsqueda, el valor 2 está ‘horneado’ en la IL de la AssemblyB B. Esto significa que si mañana actualizaré I_CONST_VALUE a 20 en el futuro. AssemblyB todavía tendría 2 hasta que lo vuelva a comstackr .
  • en el caso del valor de readonly , es como una ref a una ubicación de memoria. El valor no está horneado en la IL de AssemblyB . Esto significa que si la ubicación de la memoria se actualiza, AssemblyB obtiene el nuevo valor sin recomstackción. Entonces, si I_RO_VALUE se actualiza a 30, solo necesita construir AssemblyA . Todos los clientes no necesitan ser recomstackdos.

Entonces, si está seguro de que el valor de la constante no cambiará, use una 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, use 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 … Efectivo C # – Bill Wagner

Hay un gotcha con consts! Si hace referencia a una constante de otro ensamblaje, su valor se comstackrá 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!

Constantes

  • Las constantes son estáticas por defecto
  • Deben tener un valor en tiempo de comstackció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)

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 } } 

Esto lo explica . Resumen: const debe inicializarse en el momento de la statement, 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

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.

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 } } 

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

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

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

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 statement o por código en el constructor

Un const es una constante en tiempo de comstackció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 C # tiene más información sobre diferentes tipos de inmutabilidad

Aquí hay otro enlace que demuestra 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 comstackció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”

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?

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 defult estática. El valor no se puede cambiar desde ningún lugar (Ctor, Function, runtime, etc., en ningún lugar)

Creo que un valor const es el mismo para todos los objetos (y debe inicializarse con una expresión literal), mientras que readonly puede ser diferente para cada instanciación …

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

  • Utilice const cuando tenga una variable de un tipo que pueda conocer en tiempo de ejecución (cadena literal, int, doble, enumeraciones, …) a la que desee que tengan acceso todas las instancias o consumidores de una clase donde el valor no debe cambiar.
  • Use estática cuando tenga datos a los que quiera que tengan acceso todas las instancias o consumidores de una clase donde el valor puede cambiar.
  • Use static readonly cuando tenga una variable de un tipo que no pueda conocer en tiempo de ejecución (objetos) a la que desee que tengan acceso todas las instancias o consumidores de una clase donde el valor no debe cambiar.
  • Úselo solo 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 const es estático, pero el inverso no es verdadero.

Ambos son constantes, pero un const está disponible también en tiempo de comstackción. Esto significa que un aspecto de la diferencia es que puede usar las variables const como entrada para los constructores de atributos, pero no para las variables de solo 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; } } } 

Las variables marcadas const son poco más que macros #define fuertemente tipadas, en el momento de la comstackción las referencias de las variables const se reemplazan por valores literales en línea. Como consecuencia, solo ciertos tipos de valores primitivos incorporados se pueden usar de esta manera. Las variables marcadas de solo lectura se pueden configurar, en un constructor, en tiempo de ejecución y su read-only-ness también se aplica durante el tiempo de ejecución. Hay un pequeño costo de rendimiento asociado con esto, pero significa que puede usar readonly con cualquier tipo (incluso los 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.

La palabra clave readonly es diferente de la palabra clave const. Un campo const solo se puede inicializar en la statement del campo. Un campo de solo lectura se puede inicializar en la statement o en un constructor. Por lo tanto, los campos de solo lectura pueden tener diferentes valores según el constructor utilizado. Además, aunque un campo const es una constante de tiempo de comstackción, el campo de solo lectura se puede usar para constantes de tiempo de ejecución como en el siguiente ejemplo:

 public static readonly uint l1 = (uint) DateTime.Now.Ticks; 

La palabra clave readonly es diferente de la palabra clave const . Un campo const solo se puede inicializar en la statement del campo. Un campo de solo lectura se puede inicializar en la statement o en un constructor . Por lo tanto, los campos de solo lectura pueden tener diferentes valores según el constructor utilizado. Además, aunque un campo const es una constante de tiempo de comstackción , el campo de solo lectura se puede usar para constantes de tiempo de ejecución como en el siguiente ejemplo:

 public static readonly uint timeStamp = (uint)DateTime.Now.Ticks; 

Otra gotcha .

Como const realmente solo funciona con tipos de datos básicos, si desea trabajar con una clase, puede sentirse “forzado” a utilizar 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 te confundas con pensar que ReadOnly implica que un usuario no puede cambiar las cosas. No existe una syntax simple en C # para evitar que una instanciación de una clase tenga cambios en sus valores internos (hasta donde yo sé).

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

const es por defecto estático y necesita ser inicializado con un valor constante, que no puede ser modificado 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 comstacktion error public const string Name = string.Empty; //throws comstacktion error public readonly string Name = string.Empty; //No error, legal 

readonly se puede declarar como estático, pero no es necesario. No es necesario inicializar en el momento de la statement. Su valor puede asignarse o cambiarse usando constructor. Por lo tanto, da ventaja cuando se utiliza como miembro de la clase de instancia. Dos instancias diferentes pueden tener diferentes valores de campo readonly. Por ejemplo,

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

Entonces 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í, la instancia objOne tendrá el valor de readonly field como 5 y objTwo tiene 10. Lo cual no es posible usando const.

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

Como ejercicio, intente crear una biblioteca externa y consumirla en una aplicación de consola, luego alterar los valores en la biblioteca y volver a comstackrla (sin volver a comstackr el progtwig para el consumidor), soltar la DLL en el directorio y ejecutar el EXE manualmente, debe encontrar que la cadena constante no cambia

Constante

Necesitamos proporcionar el valor al campo const cuando está definido. El comstackdor guarda el valor de la constante en los metadatos del conjunto. Esto significa que una constante se puede definir solo 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. La verificación la realiza el comstackdor que lee solo los campos que no están escritos por ningún método que no sea el constructor.

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

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.

Un const tiene que estar codificado , donde como readonly se puede establecer en el constructor de la clase.

Const y Readonly son similares, pero no son exactamente lo mismo. Un campo const es una constante en tiempo de comstackción, lo que significa que ese valor se puede calcular en tiempo de comstackción. Un campo de solo lectura permite 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 de 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 comstackción. Sin embargo, considere el caso en el que defina un tipo y desee proporcionar algunas instancias previas a él. 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 de const, ya que los lados de la derecha no son constantes de tiempo de comstackción. Uno 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 que impida que un cliente de Color lo arruine, tal vez intercambiando los valores de Blanco y Negro. Huelga decir que esto causaría consternación para otros clientes de la clase Color. La función de “solo lectura” aborda este escenario. Simplemente introduciendo la palabra clave readonly en las declaraciones, conservamos la inicialización flexible y evitamos que el código del cliente se filtre.

 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 de const son siempre estáticos, mientras que un miembro de solo lectura puede ser estático o no, al igual que un campo regular.

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

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

y un desarrollador diferente escribió código que se basó en A:

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

Ahora, ¿puede el código que se genera depender del hecho de que AC es una constante en tiempo de comstackción? Es decir, ¿el uso de AC simplemente puede ser reemplazado por el valor 0? Si dices “sí” a esto, significa que el desarrollador de A no puede cambiar la forma en que se inicializa la CA: esto ata las manos del desarrollador de A sin permiso. Si dice “no” a esta pregunta, se perderá una optimización importante. Quizás el autor de A es positivo de que AC siempre será cero. El uso de const y readonly permite al desarrollador de A especificar el bash. Esto permite un mejor comportamiento de versiones y también un mejor rendimiento.

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

La diferencia es que el valor de un campo estático de solo lectura se establece en tiempo de ejecución, por lo que puede tener un valor diferente para diferentes ejecuciones del progtwig. Sin embargo, el valor de un campo const se establece en una constante de tiempo de comstackció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 al que apunta la referencia.

Para obtener detalles, consulte C # Preguntas más frecuentes sobre este tema: http://blogs.msdn.com/csharpfaq/archive/2004/12/03/274791.aspx

Las variables constantes se declaran y se inicializan en tiempo de comstackció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.

Un campo const solo se puede inicializar en la statement del campo. Un campo de solo lectura se puede inicializar en la statement o en un constructor.

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

Pero con un const, se doblaría en el código de la persona que llamó cuando se compiló a la persona que llamó.

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