2010-12-10 15 views
13

Hoy me sorprendí un poco cuando cambié el valor de una constante públicamente visible en una clase estática y luego reemplacé una copia anterior del ensamblado con la versión compilada recientemente. La sorpresa fue que el programa existente que hacía referencia al ensamblado no captaba el nuevo valor de la constante. Es decir, no volví a compilar el ejecutable, sino que simplemente reemplacé ese ensamblaje.En .NET, ¿por qué las constantes se evalúan en tiempo de compilación en lugar de en tiempo JIT?

Una descripción completa de mi experimento es en How constant is a constant?

voy a admitir a ser muy sorprendido por este comportamiento. Entiendo lo que está pasando, pero no entiendo por qué. ¿Existe alguna razón técnica particular por la que las constantes no puedan ser recogidas en el momento de JIT en lugar de en tiempo de compilación? ¿Hay casos en que hacer eso podría romper las cosas?

+0

Este es un comportamiento discutido en muchos libros, blogs, por lo que no es de extrañar que, de hecho :) –

+0

@lex: Curiosamente, me Nunca me encontré con una discusión sobre esto antes. Todavía me pregunto * por qué *, sin embargo. –

+1

Todavía no entiendo cuál es la ventaja de hornearlo en el ensamblaje de uso. – CodesInChaos

Respuesta

30

Se supone que las constantes son constante. Para todo el tiempo. Las constantes son cosas como el valor de pi o la cantidad de protones en un átomo de plomo.

Si su constante cambia, no era realmente una constante; use un campo readonly en su lugar.

Véase también las Directrices de diseño de la estructura, que establecen:

Use campos constantes para las constantes que nunca va a cambiar. El compilador graba los valores de los campos const directamente en el código de llamada. Por lo tanto, los valores de const nunca se pueden cambiar sin el riesgo de romper la compatibilidad.

Básicamente, cambiar una constante sin volver a compilar todo lo que depende de ella está tan roto como cambiar la firma de un método sin recompilar todo lo que depende de ello. El compilador "elabora" todo tipo de suposiciones acerca de la información sobre los metadatos a partir de ensamblajes referenciados cuando compila un ensamblado dependiente. Si realiza cualquier cambio, no puede esperar que las cosas sigan funcionando.

+0

¿El compilador JIT evalúa los campos de solo lectura y luego los trata como constantes cuando compila en código nativo? Es decir, ¿hay una diferencia de rendimiento entre usar una constante y usar un campo de solo lectura? –

+5

@Jim: No lo sé.En primer lugar, hay una buena media docena o más de compiladores JIT y no soy experto en ninguno de ellos. En segundo lugar, los compiladores JIT a menudo cambian su comportamiento en función de las cosas que suceden en el tiempo de ejecución, como si un depurador está conectado o no. En tercer lugar, si le preocupa el rendimiento, escriba el código en ambos sentidos, ejecútelo y vea si puede medir una diferencia. Si la diferencia es demasiado pequeña para medir, probablemente no sea una diferencia de la que deba preocuparse en primer lugar. –

+7

Escuché que PI ahora es exactamente 3. – ChaosPandion

1

También hay una tercera forma de declarar "constantes": una propiedad pública estática.

public static string ConstString {get{return "First test";}} 

Esto tiene la semántica de versiones de un campo de sólo lectura, pero si la fluctuación inlines el captador se convierte en una constante en tiempo JIT. Y a diferencia de const, puede usarse en tipos definidos por el usuario.

Creo que es una buena idea usar propiedades estáticas para value-types y string, pero no para clases definidas por el usuario, ya que no desea asignar una nueva instancia en cada acceso de propiedad.

He utilizado este tipo en mi FixedPoint así:

public struct FixedPoint 
{ 
    private int raw; 
    private const fracDigits=16; 

    private FixedPoint(int raw) 
    { 
    this.raw=raw; 
    } 

    public static FixedPoint Zero{get{return new FixedPoint();}} 
    public static FixedPoint One{get{return new FixedPoint(1<<fracDigits);}} 
    public static FixedPoint MaxValue{get{return new FixedPoint(int.MaxValue);}} 
} 
Cuestiones relacionadas