2014-12-05 8 views
12

Dire che ho un semplice (il più semplice?) C# programma:Costanti di stringa incorporate due volte in .Net?

class Program { 
    static void Main() { 
     System.Console.WriteLine("Hello, world"); 
    } 
} 

Se, compilo il codice e guardo il file exe risultante, vedo il "Ciao, mondo" stringa l'immagine exe come in previsto.

Se refactoring del codice per:

class Program { 
    const string Greeting = "Hello, world"; 
    static void Main() { 
     System.Console.WriteLine(Greeting); 
    } 
} 

Se compilo il codice e guardo il file exe risultante, vedo il "Ciao, mondo" stringa letterale l'immagine exe in due volte. Questo è stato sorprendente per me. Avevo l'impressione che fossero condivisi i letterali delle stringhe e che sarebbe stato visualizzato solo una volta nell'immagine. Qualcuno può spiegarlo? Forse questa seconda copia della stringa è necessaria per i metadati di riflessione?

+1

Per quanto ne so, l'operazione interna avviene durante JIT, non la compilazione per IL. Avrai lo stesso letterale nell'assemblea più e più volte. Ma in fase di esecuzione, tutti vengono compilati in riferimento allo stesso letterale internato. Vedete due istanze nel secondo caso, perché il letterale esiste due volte (una volta per la dichiarazione 'const' e poi di nuovo dove è effettivamente utilizzata). –

+1

Nel tuo secondo caso, la stringa è una costante e non cambierà mai. Il compilatore potrebbe aver deciso che è più veloce includere la stringa in cui viene utilizzata anziché prendere più di un passaggio per ottenere il valore desiderato. – NoChance

+1

Dov'è Eric Lippert quando hai bisogno di lui? –

risposta

12

Il ECMA-335 CLI specification fa luce su questo. A C# const viene dichiarato come campo static literal in IL. Dalla sezione I.8.6.1.2 (sottolineatura mia):

Il letterale vincolo promette che il valore della posizione è in realtà un valore fisso di un tipo built-in. Il valore è specificato come parte del vincolo. I compilatori sono necessari per sostituire tutti i riferimenti alla posizione con il suo valore e pertanto il VES non deve allocare spazio per la posizione. Questo vincolo, mentre logicamente applicabile a qualsiasi posizione, deve essere posizionato solo su campi statici di tipi composti. I campi contrassegnati come così contrassegnati non possono essere referenziati da CIL (devono essere allineati al loro valore costante in fase di compilazione), ma sono disponibili utilizzando la riflessione e gli strumenti che gestiscono direttamente i metadati.

Così il compilatore assume il valore costante e lo sostituisce in tutto il codice. Non è consentito fare riferimento alla memoria costante. Quello che fa da lì è ciò che fa per ogni altra stringa letterale. Fornisce uno slot nella tabella dei metadati e utilizza il codice operativo ldstr per caricare la stringa. Pertanto, il valore appare due volte nell'assieme. Una volta nel percorso di archiviazione per la costante, a cui non è possibile fare riferimento da un compilatore conforme. E un'altra volta nella tabella dei metadati.

+0

Supponendo che questo passaggio provenga dalla CLS, non dalla specifica C#, credo che il "compilatore" menzionato in questo passaggio sia il compilatore JIT, non il compilatore C#. Ma la domanda iniziale è chiedersi perché il compilatore C# emetta l'IL che fa. –

+0

@PeterDuniho L'ho letto in modo opposto, con questo passaggio che si riferisce e spiega perché il compilatore C# emette l'IL che fa. Il compilatore C# non esegue l'inlining, il compilatore JIT lo fa. È il CLR che lo aggiunge al pool interno in fase di runtime e non al compilatore C# in fase di compilazione. – rism

+0

@PeterDuniho È dalla specifica CLI ECMA-335 (aggiornata per riflettere ciò). "Compilatori" si riferisce ai compilatori di lingue che producono assembly CIL in tutto il documento. In pochi, si riferisce ai compilatori "CIL-to-native-code", che è il compilatore JIT. Il compilatore C# fa quello che fa, in parte, perché è richiesto dalla sezione citata nelle specifiche CLI. –

Problemi correlati