c# - enum - Estático readonly vs const
readonly c# (15)
He leído acerca de static readonly
campos const
y static readonly
. Tenemos algunas clases que solo contienen valores constantes. Se utiliza para varias cosas alrededor de nuestro sistema. Así que me pregunto si mi observación es correcta:
¿Deben este tipo de valores constantes ser siempre static readonly
para todo lo que es público? ¿Y solo usa const
para valores internos / protegidos / privados?
¿Que recomiendas? ¿Es posible que incluso no use static readonly
campos static readonly
, sino que use las propiedades tal vez?
Const: Const no es más que "constante", una variable cuyo valor es constante pero en tiempo de compilación. Y es obligatorio asignarle un valor. Por defecto, const es estático y no podemos cambiar el valor de una variable const en todo el programa.
Static ReadOnly: el valor de una variable de tipo Static Readonly puede asignarse en tiempo de ejecución o asignarse en tiempo de compilación y cambiarse en tiempo de ejecución. Pero el valor de esta variable solo se puede cambiar en el constructor estático. Y no se puede cambiar más. Puede cambiar solo una vez en tiempo de ejecución
Referencia: c-sharpcorner
Algunas otras cosas
const int a
- debe ser inicializado
- La inicialización debe ser en tiempo de compilación
readonly int a
- Se puede usar el valor por defecto, sin inicializar.
- La inicialización puede ser en tiempo de ejecución
Esto es solo un suplemento a las otras respuestas. No los repetiré (ahora cuatro años después).
Hay situaciones en las que una const
y una no constante tienen semántica diferente. Por ejemplo:
const int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
imprime True
, mientras que:
static readonly int y = 42;
static void Main()
{
short x = 42;
Console.WriteLine(x.Equals(y));
}
escribe False
La razón es que el método x.Equals
tiene dos sobrecargas, una que lleva un short
( System.Int16
) y otra que toma un object
( System.Object
). Ahora la pregunta es si uno o ambos se aplican con mi argumento y
.
Cuando y
es una constante de compilación (literal), el caso const
, se vuelve importante que exista una conversión implícita de int
a short
siempre que int
sea una constante, y siempre que el compilador C # verifique que su valor está dentro de El rango de un short
(que es 42
). Consulte Conversiones de expresiones constantes implícitas en la Especificación del lenguaje C #. Así que ambas sobrecargas tienen que ser consideradas. Se prefiere la sobrecarga Equals(short)
(cualquier short
es un object
, pero no todos los object
son short
). Entonces y
se convierte a short
, y se usa esa sobrecarga. Entonces Equals
compara dos valores short
de valores idénticos, y eso da true
.
Cuando y
no es una constante, no existe una conversión implícita de int
a short
. Eso es porque en general un int
puede ser demasiado grande como para caber en un short
. (Existe una conversión explícita , pero no dije Equals((short)y)
, por lo que no es relevante). Vemos que solo se aplica una sobrecarga, Equals(object)
. Así que y
está encajonado para object
. Entonces Equals
va a comparar un System.Int16
con un System.Int32
, y dado que los tipos de tiempo de ejecución ni siquiera están de acuerdo, eso dará como resultado false
.
Llegamos a la conclusión de que en algunos casos (raros), cambiar un miembro de tipo const
a un campo de static readonly
(o al contrario, cuando sea posible) puede cambiar el comportamiento del programa.
Hay una diferencia menor entre los campos const y read readly static en C # .Net
const debe inicializarse con valor en tiempo de compilación.
const es, por defecto, estático y debe inicializarse con un valor constante, que no se puede modificar más adelante. No se puede utilizar con todos los tipos de datos. Por ex DateTime. No se puede utilizar 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 static 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 declaración. Su valor puede ser asignado o cambiado usando el constructor una vez. Por lo tanto, existe la posibilidad de cambiar el valor del campo de solo lectura una vez (no importa, si es estático o no), lo que no es posible con const.
La palabra clave readonly
es diferente de la palabra clave const
. Un campo const
solo se puede inicializar en la declaración del campo. Un campo de readonly
puede inicializarse en la declaración o en un constructor. Por lo tanto, los campos de readonly
pueden tener diferentes valores dependiendo del constructor utilizado. Además, mientras que un campo const
es una constante de tiempo de compilación, el campo de readonly
se puede usar para constantes de tiempo de ejecución
Las constantes son como su nombre lo indica, los campos que no cambian y generalmente se definen de forma estática en el momento de la compilación en el código.
Las variables de solo lectura son campos que pueden cambiar bajo condiciones específicas.
Se pueden inicializar cuando se declaran por primera vez como una constante, pero generalmente se inicializan durante la construcción del objeto dentro del constructor.
No se pueden cambiar después de la inicialización, en las condiciones mencionadas anteriormente.
La lectura estática de solo lectura suena como una mala elección para mí, ya que, si es estática y nunca cambia, así que solo úsala constante pública, si puede cambiar, entonces no es una constante y luego, dependiendo de tus necesidades, puedes usar lectura -Sólo una variable regular o simplemente.
Además, otra distinción importante es que una constante pertenece a la clase, mientras que la variable de solo lectura pertenece a la instancia.
Mi preferencia es usar const siempre que pueda, lo que, como se mencionó anteriormente, se limita a expresiones literales o algo que no requiere evaluación.
Si me caliento contra esa limitación, entonces retrocedo a la lectura estática solo , con una advertencia. Por lo general, usaría una propiedad estática pública con un captador y un campo de lectura estática privada de respaldo, como menciona Marc here .
Un campo de solo lectura estático es ventajoso cuando se expone a otros ensamblajes un valor que podría cambiar en una versión posterior.
Por ejemplo, supongamos que el conjunto X
expone una constante de la siguiente manera:
public const decimal ProgramVersion = 2.3;
Si el ensamblaje Y
referencia a X
y utiliza esta constante, el valor 2.3 se incluirá en el ensamblaje Y
cuando se compile. Esto significa que si X
se vuelve a compilar con la constante establecida en 2.4, Y
seguirá utilizando el valor anterior de 2.3 hasta que Y
se vuelva a compilar. Un campo de solo lectura estático evita este problema.
Otra forma de ver esto es que cualquier valor que pueda cambiar en el futuro no es constante por definición y, por lo tanto, no debe representarse como uno solo.
Una cosa a tener en cuenta es que const se restringe a tipos primitivos / de valor (la excepción son las cadenas)
Yo usaría static readonly
si el Consumidor está en un ensamblaje diferente. Tener a la const
y al consumidor en dos montajes diferentes es una buena forma de dispararte en el pie .
const
- el valor debe ser dado a la declaración
- constante de tiempo de compilación
solo lectura:
- el valor puede darse en la declaración o durante el tiempo de ejecución utilizando constructores. El valor puede variar dependiendo del constructor utilizado.
- constante de tiempo de ejecución
const
y readonly
son similares, pero no son exactamente iguales.
Un campo const
es una constante de tiempo de compilación, lo que significa que ese valor se puede calcular en tiempo de compilación. Un campo de readonly
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 readonly
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;
}
Dado que valores como 3.14 y 0 son constantes en tiempo de compilación. Sin embargo, considere el caso en el que define un tipo y desea proporcionar algunas instancias prefabricadas de é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 const, ya que los lados derechos no son constantes de tiempo de compilació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, green, blue) = (r, g, b);
}
Pero entonces no hay nada que impida que un cliente de Color se mezcle 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 característica "solo lectura" aborda este escenario.
Simplemente introduciendo la palabra clave de readonly
en las declaraciones, conservamos la inicialización flexible y 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, green, blue) = (r, g, 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 regular.
Es posible usar una sola palabra clave para estos dos propósitos, pero esto conduce a problemas de versión 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 se basaba en A:
public class B
{
static void Main() => Console.WriteLine(A.C);
}
Ahora, ¿puede el código que se genera depender del hecho de que AC es una constante de compilación? Es decir, ¿puede el uso de AC simplemente ser reemplazado por el valor 0? Si dices "sí" a esto, entonces eso significa que el desarrollador de A no puede cambiar la forma en que AC se inicializa, lo que une las manos del desarrollador de A sin permiso.
Si dice "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 que el desarrollador de A especifique la intención. Esto permite un mejor comportamiento de las versiones y también un mejor rendimiento.
public static readonly
campos de public static readonly
son un poco inusuales; public static
propiedades public static
(con solo una get
) serían más comunes (quizás respaldadas por un campo de private static readonly
).
const
valores const
se graban directamente en el sitio de la llamada; esto es de doble filo:
- es inútil si el valor se recupera en tiempo de ejecución, tal vez desde config
- Si cambia el valor de una constante, debe reconstruir todos los clientes.
- pero puede ser más rápido, ya que evita una llamada al método ...
- ... que a veces podría haber sido incluido por el JIT de todos modos
Si el valor nunca cambia, entonces const es correcto - Zero
etc., haga constantes razonables; p Aparte de eso, las propiedades static
son más comunes.
Const : los valores de las variables const deben definirse junto con la declaración y después de eso no cambiarán. Las const son implícitamente estáticas, así que sin crear una instancia de clase podemos acceder a ellas. Esto tiene un valor en tiempo de compilación.
ReadOnly : valores de solo lectura que podemos definir al declarar y usar el constructor en tiempo de ejecución. Las variables de solo lectura no pueden acceder sin instancia de clase.
Lectura estática solo : valores de variable estática de solo lectura que podemos definir mientras declaramos y solo a través del constructor estático pero no con ningún otro constructor. A estas variables también podemos acceder sin crear una instancia de clase (como variables estáticas)
La lectura estática solo será una mejor opción si tenemos que consumir las variables en diferentes ensamblajes. Por favor, revise los detalles completos en el siguiente enlace
https://www.stum.de/2009/01/14/const-strings-a-very-convenient-way-to-shoot-yourself-in-the-foot/
Solo lectura estática : el valor se puede cambiar a través del constructor static
en tiempo de ejecución. Pero no a través de la función miembro.
Constante : Por defecto static
. El valor no se puede cambiar desde ningún lugar (Ctor, Función, tiempo de ejecución, etc., en ningún lugar).
Solo lectura : el valor se puede cambiar a través del constructor en tiempo de ejecución. Pero no a través de la función miembro.
Puedes echar un vistazo a mi repo: tipos de propiedades C # .