¿Cuál es la diferencia entre const
y readonly
en C #?
¿Cuándo usarías uno sobre el otro?
¿Cuál es la diferencia entre const
y readonly
en C #?
¿Cuándo usarías uno sobre el otro?
Respuestas:
Aparte de la aparente diferencia de
const
VS readonly
puede calcularse dinámicamente pero debe asignarse antes de que el constructor salga ... después de eso se congela.static
. Utiliza una 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 utiliza estos valores en el código. Cuando esto se compila,
const
valor, es como una búsqueda de reemplazo, el valor 2 se "cuece" en la AssemblyB
IL. 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 compilar .readonly
valor, es como una ref
ubicación de memoria. El valor no está incluido en AssemblyB
la IL de. Esto significa que si la ubicación de la memoria se actualiza, AssemblyB
obtiene el nuevo valor sin recompilación. Entonces, si I_RO_VALUE
se 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
static
punto parece ser el punto más importante y útil -consts are implicitly static
readonly
Las variables se pueden cambiar fuera del constructor (reflexión). Es solo el compilador el que intenta impedir que modifiques la var fuera del constructor.
readonly
No 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.Empty
a "Hello, world!"
, pero todavía no afirmaría que esto hace string.Empty
modificable, o que el código no debe suponer que string.Empty
siempre habrá una cadena de longitud cero.
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!
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
}
}
string
que pueda usar como constante?
const
tipos de referencia que no sean cadena, pero la constante solo puede tener el valor null
.
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
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
}
}
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 const
palabra clave y deben inicializarse 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 un readonly
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
static
(son implícitamente estáticos)solo lectura
static const int i = 0;
const
no se pueden hacer declaraciones dentro de los métodos?
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.
Aquí hay otro enlace que demuestra cómo const no es segura para la versión o relevante para los tipos de referencia.
Resumen :
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.)
Otro problema: los valores de solo lectura se pueden cambiar mediante un código "desviado" 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 privado de solo lectura heredado en C # usando la reflexión?
Creo que un const
valor 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 en nuestra oficina proporcionó la siguiente guía sobre cuándo usar const, static y readonly:
Una nota final: un campo constante es estático, pero lo inverso no es cierto.
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; }
}
}
cuando usar const
oreadonly
const
readonly
App.config
, pero una vez que se inicializa no se puede cambiarLas 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.
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).
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.
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.
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
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.
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
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.
Const : valor constante absoluto durante el tiempo de vida de la aplicación.
Solo lectura : se puede cambiar en tiempo de ejecución.
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).