Pregunta

Error del compilador CS0283 indica que solo el Los tipos básicos de POD (así como cadenas, enumeraciones y referencias nulas) pueden declararse como const . ¿Alguien tiene una teoría sobre la justificación de esta limitación? Por ejemplo, sería bueno poder declarar valores constantes de otros tipos, como IntPtr.

Creo que el concepto de const es en realidad azúcar sintáctico en C #, y que simplemente reemplaza cualquier uso del nombre con el valor literal. Por ejemplo, dada la siguiente declaración, cualquier referencia a Foo sería reemplazada por '' foo '' en tiempo de compilación.

const string Foo = "foo";

Esto descartaría cualquier tipo mutable, por lo que tal vez eligieron esta limitación en lugar de tener que determinar en el momento de la compilación si un tipo determinado es mutable?

¿Fue útil?

Solución

De la especificación C #, capítulo 10.4 - Constantes :
(10.4 en la especificación C # 3.0, 10.3 en la versión en línea para 2.0)

  

Una constante es un miembro de la clase que representa un valor constante: un valor que se puede calcular en tiempo de compilación.

Esto básicamente dice que solo puedes usar expresiones que consisten únicamente en literales. Cualquier llamada a cualquier método, los constructores (que no se pueden representar como literales IL puros) no se pueden usar, ya que no hay forma de que el compilador realice esa ejecución y, por lo tanto, calcule los resultados en tiempo de compilación. Además, dado que no hay forma de etiquetar un método como invariante (es decir, hay un mapeo uno a uno entre entrada y salida), la única forma para que el compilador haga esto sería analizar el IL para ver si depende de otras cosas que no sean los parámetros de entrada, el caso especial maneja algunos tipos (como IntPtr), o simplemente no permite todas las llamadas a ningún código.

IntPtr, como ejemplo, aunque es un tipo de valor, sigue siendo una estructura y no uno de los literales incorporados. Como tal, cualquier expresión que use un IntPtr necesitará llamar al código en la estructura IntPtr, y esto es lo que no es legal para una declaración constante.

El único ejemplo de tipo de valor constante legal que se me ocurre sería uno que se inicializa con ceros simplemente declarándolo, y eso no es útil.

En cuanto a cómo el compilador trata / usa las constantes, usará el valor calculado en lugar del nombre constante en el código.

Por lo tanto, tiene el siguiente efecto:

  • Ninguna referencia al nombre constante original, la clase en la que se declaró o el espacio de nombres se compila en el código en esta ubicación
  • Si descompila el código, tendrá números mágicos, simplemente porque la "referencia" original para la constante, como se mencionó anteriormente, no está presente, solo el valor de la constante
  • El compilador puede usar esto para optimizar, o incluso eliminar, código innecesario. Por ejemplo, if (SomeClass.Version == 1) , cuando SomeClass.Version tiene el valor de 1, de hecho eliminará la instrucción if y mantendrá el bloque de código en ejecución. Si el valor de la constante no es 1, se eliminará toda la instrucción if y su bloque.
  • Dado que el valor de una constante se compila en el código, y no una referencia a la constante, el uso de constantes de otros ensamblados no actualizará automáticamente el código compilado de ninguna manera si el valor de la constante cambia (lo que debería no!)

En otras palabras, con el siguiente escenario:

  1. Asamblea A, contiene una constante llamada '' Versión '', que tiene un valor de 1
  2. Conjunto B, contiene una expresión que analiza el número de versión del conjunto A de esa constante y lo compara con 1, para asegurarse de que pueda funcionar con el conjunto
  3. Alguien modifica el ensamblado A, aumentando el valor de la constante a 2, y reconstruye A (pero no B)

En este caso, el ensamblado B, en su forma compilada, seguirá comparando el valor de 1 a 1, porque cuando se compiló B, la constante tenía el valor 1.

De hecho, si ese es el único uso de cualquier cosa desde el ensamblado A en el ensamblado B, el ensamblado B se compilará sin depender del ensamblado A. La ejecución del código que contiene esa expresión en el ensamblado B no cargará el ensamblado A.

Por lo tanto, las constantes solo deben usarse para cosas que nunca cambiarán. Si es un valor que podría cambiar o cambiará en algún momento en el futuro, y no puede garantizar que todos los demás ensambles se reconstruyan simultáneamente, un campo de solo lectura es más apropiado que una constante.

Entonces esto está bien:

  • public const Int32 NumberOfDaysInAWeekInGregorianCalendar = 7;
  • public const Int32 NumberOfHoursInADayOnEarth = 24;

mientras esto

Otros consejos

  

¿Alguien tiene una teoría sobre la justificación de esta limitación?

Si se permite que sea solo una teoría, mi teoría es que los valores constantes de los tipos primitivos pueden expresarse en parámetros de código de operación literales en el MSIL ... pero los valores de otros tipos no primitivos no pueden, porque MSIL no t tiene la sintaxis para expresar el valor de un tipo definido por el usuario como literal.

  

Creo que el concepto de const es en realidad azúcar sintáctico en C #, y que simplemente reemplaza cualquier uso del nombre con el valor literal

¿Qué hace el compilador con los objetos const en otros idiomas?

Puede usar solo lectura para tipos mutables que se evaluarán en tiempo de ejecución. Consulte este artículo para conocer las diferencias.

Los concursos

están limitados a números y cadenas en C # porque el compilador reemplaza la variable con el valor literal en el MSIL. En otras palabras, cuando escribes:

const string myName = "Bruce Wayne";
if (someVar == myName)
{
   ...
}

en realidad se trata como

if (someVar == "Bruce Wayne")
{
   ...
}

y sí, el compilador de C # es lo suficientemente inteligente como para tratar el operador de igualdad (==) en cadenas como

string1.Equals(string2)

Me parece que solo los tipos de valor se pueden expresar como una constante (con la excepción de las cadenas, que se encuentra en algún lugar entre el valor y el tipo de objeto).

Está bien para mí: los objetos (referencias) deben asignarse en el montón pero las constantes no se asignan en absoluto (ya que se reemplazan en tiempo de compilación).

En resumen, todos los tipos simples, enumeraciones y cadenas son inmutables, pero un Struct, por ejemplo, no lo es. Puede tener una estructura con estado mutable (campos, propiedades, incluso referencias a tipos de referencia). Por lo tanto, el compilador no puede asegurarse (en tiempo de compilación) de que el estado interno de una variable Struct no se pueda cambiar. Por lo tanto, el compilador debe asegurarse de que un tipo es, por definición, inmutable para usarse en una expresión constante.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top