2010-12-10 19 views
13

Oggi ho avuto un po 'di sorpresa quando ho cambiato il valore di una costante pubblicamente visibile in una classe statica e poi ho sostituito una vecchia copia dell'assieme con la versione appena compilata. La sorpresa è stata che il programma esistente che faceva riferimento all'assembly non ha rilevato il nuovo valore della costante. Cioè, non ho ricompilato l'eseguibile ma piuttosto ho appena sostituito quell'unico assieme.In .NET, perché le costanti vengono valutate in fase di compilazione anziché in fase di JIT?

Una descrizione completa del mio esperimento è a How constant is a constant?

devo ammettere di essere molto sorpreso da questo comportamento. Capisco cosa sta succedendo, ma non capisco why. C'è una ragione tecnica particolare per cui le costanti non possono essere raccolte al momento del JIT piuttosto che compilare il tempo? Ci sono casi in cui fare ciò potrebbe rompere le cose?

+0

Questo è un comportamento descritto in troppi libri, blog, quindi non è così sorprendente in realtà :) –

+0

@lex: Stranamente, ho Non ho mai avuto una discussione su di esso prima. Mi chiedo ancora * perché *, però. –

+1

Ancora non capisco quale sia il vantaggio di cuocerlo nell'assemblaggio. – CodesInChaos

risposta

30

Le costanti devono essere costante. Per tutte le volte. Le costanti sono cose come il valore di pi, o il numero di protoni in un atomo di piombo.

Se le modifiche continue, , non erano realmente una costante; utilizzare invece un campo readonly.

puoi anche consultare i Linee guida di progettazione quadro, in cui si afferma:

Utilizzare i campi di costanti per le costanti che non cambierà mai. Il compilatore masterizza i valori dei campi const direttamente nel codice chiamante. Pertanto i valori const non possono mai essere modificati senza il rischio di rompere la compatibilità.

In sostanza, modificare una costante senza ricompilare tutto ciò che dipende da esso è altrettanto rovinato come cambiare la firma di un metodo senza ricompilare tutto ciò che dipende da esso. Il compilatore "inserisce tutti i tipi di ipotesi sulle informazioni sui metadati dagli assembly referenziati quando compila un assembly dipendente. Se fai cambiare in qualsiasi, non puoi aspettarti che le cose continuino semplicemente a funzionare.

+0

Il compilatore JIT valuta i campi di sola lettura e li considera come costanti durante la compilazione in codice nativo? Cioè, c'è una differenza di prestazioni tra l'utilizzo di una costante e l'utilizzo di un campo di sola lettura? –

+5

@Jim: non lo so.Prima di tutto, ci sono una buona mezza dozzina o più compilatori JIT e io sono un esperto di nessuno di loro. In secondo luogo, i compilatori JIT cambiano spesso il loro comportamento in base a cose che accadono in fase di esecuzione, ad esempio se un debugger è collegato o meno. Terzo, se sei preoccupato per le prestazioni, scrivi il codice in entrambi i modi, eseguilo e vedi se riesci a misurare una differenza. Se la differenza è troppo piccola per essere misurata, probabilmente non è una differenza di cui dovresti preoccuparti in primo luogo. –

+7

Ho sentito che PI ora è esattamente 3. – ChaosPandion

1

C'è anche un terzo modo per dichiarare "costanti": una proprietà statica pubblica.

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

Questo ha la semantica delle versioni di un campo di sola lettura, ma se il jitter Inlines il getter diventa una costante jit-tempo. E a differenza di const può essere utilizzato su tipi definiti dall'utente.

Penso che sia una buona idea utilizzare le proprietà statiche per i tipi di valore e la stringa, ma non per le classi definite dall'utente, poiché non si desidera assegnare una nuova istanza ad ogni accesso di proprietà.

Ho usato questo nel mio tipo PUNTOFISSO in questo modo:

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);}} 
} 
Problemi correlati