Pregunta Static solo contra const


He leído acerca de const y static readonly campos. 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 static readonly para todo lo que es público? Y solo usa const para valores internos / protegidos / privados?

¿Que recomiendas? Debería incluso no usar static readonly campos, sino más bien usar propiedades tal vez?


1201
2018-04-16 11:21


origen


Respuestas:


public static readonly los campos son un poco inusuales; public static propiedades (con solo un get) sería más común (quizás respaldado por private static readonly campo).

const los valores se graban directamente en el sitio de llamada; 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 será Nunca cambiar, entonces const está bien - Zero etc. hacen consignas razonables; p Aparte de eso, static las propiedades son más comunes.


828
2018-04-16 11:24



yo usaría static readonly Si el Consumidor está en un ensamble diferente. Tener el const y el Consumidor en dos conjuntos diferentes es una buena manera de disparate en el pie.


199
2018-04-16 12:57



Algunas otras cosas

const int a 

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

readonly int a

  • puede usar el valor predeterminado, sin inicializar
  • la inicialización puede estar en tiempo de ejecución

173
2018-04-16 11:36



Esto es solo un suplemento a las otras respuestas. No los repetiré (ahora cuatro años después).

Hay situaciones donde const y un non-const tiene 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 uno que toma una object (System.Object) Ahora la pregunta es si uno o ambos se aplican con mi y argumento.

Cuando y es una constante en tiempo de compilación (literal), el const caso, se vuelve importante que exista una conversión implícita de  int  a  short siempre que el int es una constante, y siempre que el compilador de C # verifique que su valor está dentro del rango de un short (cual 42 es). Ver Conversiones de expresiones constantes implícitas en la especificación del lenguaje C #. Entonces ambas sobrecargas deben ser consideradas. La sobrecarga Equals(short) es preferido (cualquier short es un object, pero no todos object son short) Asi que y se convierte a shorty esa sobrecarga se usa Entonces Equals compara dos short de idéntico valor, y eso da true.

Cuando y no es una constante, no implícito conversión de int a short existe Eso es porque en general un intpuede ser demasiado grande para caber en un short. (Un explícito la conversión existe, pero no dije Equals((short)y), entonces eso no es relevante.) Vemos que solo se aplica una sobrecarga, el Equals(object) uno. Asi que y está en caja para object. Entonces Equals va a comparar una System.Int16 a un System.Int32, y dado que los tipos de tiempo de ejecución ni siquiera están de acuerdo, eso producirá false.

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


151
2017-09-11 14:52



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


82
2018-04-16 11:28



los readonly palabra clave es diferente de la const palabra clave. UN const el campo solo se puede inicializar en la declaración del campo. UN readonly el campo se puede inicializar en la declaración o en un constructor. Por lo tanto, readonly los campos pueden tener diferentes valores según el constructor utilizado. Además, mientras const campo es una constante en tiempo de compilación, el readonly campo se puede utilizar para constantes de tiempo de ejecución

Breve y clara referencia de MSDN aquí


23
2017-11-14 18:58



Solo lectura estática : El valor se puede cambiar a través de static constructor 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 repositorio: Tipos de propiedad C #.


16
2018-01-12 17:14



const y readonly son similares, pero no son exactamente lo mismo.

UN const campo es una constante en tiempo de compilación, lo que significa que ese valor se puede calcular en tiempo de compilación. UN readonly campo 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 readonly el campo no puede ser cambiado

Por ejemplo, const los miembros 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 compilació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 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 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 presentando el readonly palabra clave en las declaraciones, preservamos la inicialización flexible a la vez que evitamos que el código del cliente se desperdicie.

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(A.C);
}

Ahora, ¿puede el código que se genera depender del hecho de que A.C es una constante en tiempo de compilación? Es decir, ¿puede el uso de A.C simplemente reemplazarse por el valor 0? Si dices "sí" a esto, significa que el desarrollador de A no puede cambiar la forma en que se inicializa A.C. 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 sea positivo en que A.C siempre será cero. El uso de const y readonly permite al desarrollador de A especificar el intento. Esto permite un mejor comportamiento de versiones y también un mejor rendimiento.


13
2017-09-28 08:19