Static solo contra const

He leído acerca de const y static readonly campos de static readonly . Tenemos algunas clases que contienen solo valores constantes. Usado para varias cosas en nuestro sistema. Entonces me pregunto si mi observación es correcta:

¿Debería este tipo de valores constantes ser siempre de static readonly para todo lo que es público? ¿Y solo usa const para valores internos / protegidos / privados?

¿Que recomiendas? ¿Debo tal vez incluso no usar campos static readonly , sino usar propiedades tal vez?

public static readonly campos public static readonly son un poco inusuales; public static propiedades public static (con solo un get ) serían más comunes (quizás respaldadas por un campo private static readonly ).

const valores de const se graban directamente en el sitio de llamadas; esto es de doble filo

  • es inútil si el valor se obtiene en el tiempo de ejecución, quizás desde la configuración
  • si cambia el valor de una const, necesita reconstruir todos los clientes
  • pero puede ser más rápido, ya que evita una llamada a un método …
  • … que a veces puede haber sido incluido por el JIT de todos modos

Si el valor nunca cambiará, entonces const está bien: Zero etc. hacen contrapartidas razonables; p Aparte de eso, las propiedades static son más comunes.

static readonly si el consumidor está en un ensamblaje diferente. Tener la const y el Consumer en dos ensambles diferentes es una buena forma de dispararte en el pie .

Algunas otras cosas

const int a

  • debe ser inicializado
  • la inicialización debe estar en tiempo de comstackción

readonly int a

  • puede usar el valor predeterminado, sin inicializar
  • la inicialización puede estar 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 un const y un no const tienen una 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 toma en short ( System.Int16 ) y una 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 en tiempo de comstackción (literal), en este caso, es importante que exista una conversión implícita de int a short siempre que int sea ​​una constante, y siempre que el comstackdor de C # verifique que su valor está dentro el rango de un short (que 42 es). Consulte Conversiones de expresiones constantes implícitas en la Especificación del lenguaje C #. Entonces ambas sobrecargas deben ser consideradas. Se prefiere la sobrecarga Equals(short) (cualquier short es un object , pero no todos los object son short ). Entonces y se convierte en short , y esa sobrecarga se usa. Entonces Equals compara dos short de valor idéntico, y eso da true .

Cuando y no es una constante, no existe una conversión implícita de int a short . Esto se debe a que, en general, una int puede ser demasiado grande 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, la Equals(object) uno. Entonces, y está en caja 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 arrojará resultados false .

Concluimos que en algunos casos (raros), cambiar un miembro de tipo const a un campo de static readonly (o de otra manera, cuando eso es posible) puede cambiar el comportamiento del progtwig.

Una cosa a tener en cuenta es que const está restringido a tipos de primitiva / valor (la excepción son las cadenas)

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 readonly se puede inicializar en la statement o en un constructor. Por lo tanto, los campos de readonly 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 readonly se puede usar para constantes de tiempo de ejecución

Breve y clara referencia de MSDN aquí

Sólo 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.

Puede echar un vistazo a mis tipos de propiedad repo: C # .

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

Dado 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, green, blue) = (r, g, b); } 

Pero entonces no hay nada que impida que un cliente de Color lo arruine, quizás 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, green, blue) = (r, g, 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.

Mi preferencia es usar const cada vez que puedo, que como se mencionó anteriormente está limitado a expresiones literales o algo que no requiere evaluación.

Si me enfrento a esa limitación, entonces retrocedo a estática de solo lectura , con una advertencia. En general, utilizaría una propiedad estática pública con un getter y un campo private private static readonly como Marc menciona aquí .

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, suponga que el conjunto X expone una constante de la siguiente manera:

 public const decimal ProgramVersion = 2.3; 

Si el conjunto Y referencia a X y utiliza esta constante, el valor 2.3 se horneará en el conjunto Y cuando se compile. Esto significa que si X se vuelve a comstackr con la constante establecida en 2.4, Y seguirá usando el valor anterior de 2.3 hasta que se recompile Y 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, por lo que no debe representarse como tal.

Const: Const no es más que “constante”, una variable cuyo valor es constante pero en tiempo de comstackción. Y es obligatorio asignarle un valor. Por defecto, un const es estático y no podemos cambiar el valor de una variable const a lo largo de todo el progtwig.

Static ReadOnly: un valor de variable de tipo Static Readonly puede asignarse en tiempo de ejecución o asignarse en tiempo de comstackción y modificarse 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

const:

  1. el valor debe darse en la statement
  2. tiempo de comstackción constante

solo lectura:

  1. el valor puede darse al declarar o durante el tiempo de ejecución utilizando constructores. El valor puede variar según el constructor utilizado.
  2. tiempo de ejecución constante

Hay una pequeña diferencia entre const y static readonly fields en C # .Net

const debe inicializarse con valor en tiempo de comstackción.

const es por defecto estático y necesita ser inicializado con un valor constante, que no puede ser modificado más adelante. 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 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 statement. Su valor se puede asignar o cambiar usando el constructor una vez. Entonces, existe la posibilidad de cambiar el valor del campo readonly una vez (no importa, si es estático o no), lo que no es posible con const.

Las constantes son como su nombre lo indica, campos que no cambian y generalmente se definen estáticamente en tiempo de comstackción en el código.

Las variables de solo lectura son campos que pueden cambiar bajo condiciones específicas.

Pueden inicializarse cuando los declaras 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 me suena como una mala elección ya que, si es estática y nunca cambia, simplemente utilícela const pública, si puede cambiar, entonces no es una constante y luego, dependiendo de sus necesidades, puede usar read -solo o solo una variable regular.

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.