Domanda

Errore del compilatore CS0283 indica che solo il i tipi POD di base (nonché stringhe, enum e riferimenti null) possono essere dichiarati come const . Qualcuno ha una teoria sulla logica di questa limitazione? Ad esempio, sarebbe bello poter dichiarare valori const di altri tipi, come IntPtr.

Credo che il concetto di const sia in realtà zucchero sintattico in C #, e che sostituisca semplicemente qualsiasi uso del nome con il valore letterale. Ad esempio, data la seguente dichiarazione, qualsiasi riferimento a Foo verrebbe sostituito con "pippo". al momento della compilazione.

const string Foo = "foo";

Questo escluderebbe qualsiasi tipo mutabile, quindi forse hanno scelto questa limitazione piuttosto che dover determinare al momento della compilazione se un determinato tipo è mutabile?

È stato utile?

Soluzione

Dalla Specifica C #, capitolo 10.4 - Costanti :
(10.4 nella specifica C # 3.0, 10.3 nella versione online per 2.0)

  

Una costante è un membro della classe che rappresenta un valore costante: un valore che può essere calcolato al momento della compilazione.

Questo in sostanza dice che puoi usare solo espressioni composte esclusivamente da letterali. Non è possibile utilizzare chiamate a metodi, costruttori (che non possono essere rappresentati come letterali IL puri), poiché non è possibile per il compilatore eseguire tale esecuzione e quindi calcolare i risultati al momento della compilazione. Inoltre, poiché non esiste alcun modo per contrassegnare un metodo come invariante (ovvero esiste una mappatura uno-a-uno tra input e output), l'unico modo per il compilatore di fare ciò sarebbe analizzare l'IL per vedere se dipende da cose diverse dai parametri di input, il caso speciale gestisce alcuni tipi (come IntPtr) o semplicemente non consente ogni chiamata a qualsiasi codice.

IntPtr, ad esempio, sebbene sia un tipo di valore, è ancora una struttura e non uno dei letterali incorporati. Pertanto, qualsiasi espressione che utilizza IntPtr dovrà chiamare il codice nella struttura IntPtr, e questo è ciò che non è legale per una dichiarazione costante.

L'unico esempio di tipo di valore di costante legale che mi viene in mente sarebbe uno che viene inizializzato con zero semplicemente dichiarandolo, e non è molto utile.

Per quanto riguarda il modo in cui il compilatore tratta / usa le costanti, utilizzerà il valore calcolato al posto del nome della costante nel codice.

Quindi, hai il seguente effetto:

  • Nessun riferimento al nome della costante originale, alla classe in cui è stato dichiarato o allo spazio dei nomi, viene compilato nel codice in questa posizione
  • Se decompili il codice, conterrà numeri magici, semplicemente perché l'originale "riferimento" per la costante, come detto sopra, non è presente solo il valore della costante
  • Il compilatore può utilizzarlo per ottimizzare o addirittura rimuovere il codice non necessario. Ad esempio, if (SomeClass.Version == 1) , quando SomeClass.Version ha il valore 1, rimuoverà di fatto l'istruzione if e manterrà il blocco di codice in esecuzione. Se il valore della costante non è 1, allora l'intera istruzione if e il suo blocco verranno rimossi.
  • Poiché il valore di una costante viene compilato nel codice e non un riferimento alla costante, l'utilizzo di costanti da altri assiemi non aggiornerà automaticamente il codice compilato in alcun modo se il valore della costante dovesse cambiare (cosa che dovrebbe no!)

In altre parole, con il seguente scenario:

  1. L'Assemblea A, contiene una costante denominata "Versione", con un valore di 1
  2. Assembly B, contiene un'espressione che analizza il numero di versione dell'assembly A da quella costante e lo confronta con 1, per assicurarsi che funzioni con l'assembly
  3. Qualcuno modifica l'assieme A, aumentando il valore della costante a 2 e ricostruisce A (ma non B)

In questo caso, l'assembly B, nella sua forma compilata, confronterà ancora il valore da 1 a 1, perché quando B è stata compilata, la costante aveva il valore 1.

In effetti, se questo è l'unico utilizzo di qualsiasi cosa dall'assemblaggio A nell'assemblaggio B, l'assemblaggio B verrà compilato senza una dipendenza dall'assemblaggio A. L'esecuzione del codice contenente tale espressione nell'assemblaggio B non caricherà l'assemblaggio A. p>

Le costanti dovrebbero quindi essere utilizzate solo per cose che non cambieranno mai. Se si tratta di un valore che potrebbe cambiare o cambierà in futuro e non è possibile garantire che tutti gli altri assembly vengano ricostruiti contemporaneamente, un campo di sola lettura è più appropriato di una costante.

Quindi va bene:

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

mentre questo

Altri suggerimenti

  

Qualcuno ha una teoria sulla logica di questa limitazione?

Se è permesso essere solo una teoria, la mia teoria è che i valori const di tipi primitivi possono essere espressi in parametri letterali opcode nella MSIL ... ma i valori di altri tipi non primitivi non possono, perché MSIL non lo fa ' t ha la sintassi per esprimere il valore di un tipo definito dall'utente come letterale.

  

Credo che il concetto di const sia in realtà zucchero sintattico in C # e che sostituisca qualsiasi uso del nome con il valore letterale

Cosa fa il compilatore con oggetti const in altre lingue?

È possibile utilizzare di sola lettura per tipi mutabili che mi verranno valutati in fase di esecuzione. Vedi questo articolo per le differenze.

I

cons sono limitati a numeri e stringhe in C # perché il compilatore sostituisce la variabile con il valore letterale in MSIL. In altre parole quando scrivi:

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

viene in realtà trattato come

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

e sì, il compilatore C # è abbastanza intelligente da trattare l'operatore di uguaglianza (==) sulle stringhe come

string1.Equals(string2)

Mi sembra che solo i tipi di valore possano essere espressi come una costante (ad eccezione delle stringhe, che si collocano tra valore e tipo di oggetto).

Per me è OK: gli oggetti (riferimenti) devono essere allocati sull'heap ma le costanti non sono affatto allocate (poiché sono sostituite in fase di compilazione).

In breve, tutti i tipi semplici, enumerazioni e stringhe sono immutabili, ma non lo è per esempio Struct. È possibile avere un Struct con stato modificabile (campi, proprietà, persino riferimenti a Tipi di riferimento). Quindi il compilatore non può assicurarsi (al momento della compilazione) che lo stato interno di una variabile Struct non possa essere modificato. Quindi il compilatore deve essere sicuro che un tipo sia per definizione immutabile per essere usato in un'espressione costante.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top