2013-04-06 15 views
5

Perché gli usi di const vengono sostituiti dai loro valori in fase di compilazione ma sono ancora inclusi nell'assembly? Almeno questo è ciò che mostra IL DASM e Reflector..NET const che influisce sulla dimensione del assembly compilato

Attualmente sto usando const per la definizione di molti numeri magici e stringhe per rendere più semplice la modifica del codice senza influire sulle prestazioni di runtime.

Ora so che ciò non influisce sulla memoria utilizzata ma influenza ancora le dimensioni del gruppo compilato, ad esempio cruciale per le app per dispositivi mobili.

Un altro svantaggio è che altre persone comprendono più facilmente i numeri magici quando guardano il codice smontato.

Sono davvero interessato al motivo per cui il compilatore (Mono e .NET) fa esattamente questo?

+0

possibile duplicato di [Qual è la differenza tra const e readonly?] (Http://stackoverflow.com/questions/55984/what-is-the-difference-tra between-const-and-readonly) –

+1

Non sono d'accordo con il precedente suggerimento duplicato. Questa domanda è molto più specifica di un semplice confronto 'const' contro' readonly'. – stakx

+1

Sono d'accordo con il disaccordo di stakx. – stfx

risposta

6

Questo comportamento è specificato nello ECMA-335 standard (di cui sia .NET che Mono sono implementazioni). Citando dalla sezione II.22.9, "costante":

Notare che Constant informazioni non influenza direttamente comportamento in esecuzione, anche se è visibile tramite riflessione (e quindi può essere utilizzato per implementare la funzionalità come quella fornita da System.Enum.ToString). I compilatori controllano queste informazioni, al momento della compilazione, quando importano i metadati, ma il valore della costante stessa, se usato, viene incorporato nel flusso CIL emesso dal compilatore. Non ci sono istruzioni CIL per accedere alla tabella Constant in fase di esecuzione.

Cioè, const valori sono "inline" (forse perché possono essere, e per motivi di prestazioni), ma sono tenuti in metadati comunque in modo che possano essere controllati dai compilatori e strumenti.

Se i metadati sono stati emessi per la const -ness di campi, ciò avrebbe queste conseguenze (possibilmente tra gli altri — questi sono solo due esempi):

  • compilatori o strumenti come riflettore non riusciva più a distinguere tra campi regolari e campi const.
  • Se si è verificato un campo utilizzando System.Reflection, non sarà più possibile utilizzare FieldInfo.IsLiteral property.
+0

+1 per la citazione e la spiegazione dello standard ECMA. –

+0

+1 Ancora non sono sicuro di come ciò possa sollevare le sopracciglia dato che per primo non mi aspettavo di trovare i campi 'const' tramite Reflection. Anche divertente 'System.Enum.ToString' è probabilmente l'implementazione più lenta per ottenere la rappresentazione della stringa enum. Ma suppongo che l'ECMA lo dica .. – stfx

+0

@stfx: mi sono sbagliato con l'ultima parte della mia risposta. Non è che i campi 'const' non siano più individuabili attraverso i metadati; non saresti in grado di distinguerli dai campi regolari. Ho corretto la mia risposta. – stakx

2

L'aumento delle dimensioni dell'assieme è dovuto essenzialmente al compilatore C# che emette ulteriori metadati su const -ness.


Quale risultato ti aspetti da questo breve programma?

class Program 
{ 
    public const int C = 0; 
    public  int F = 0; 

    static void Main(string[] args) 
    { 
     foreach (FieldInfo field in typeof(Program).GetFields()) 
     { 
      Console.WriteLine("{0}: IsLiteral = {1}", field.Name, field.IsLiteral); 
     } 
    } 
} 

L'uscita effettiva è:

C: IsLiteral = True 
F: IsLiteral = False 

che corrisponde alle dichiarazioni del # sorgente C esattamente: due campi, uno dei quali const.

Ora diciamo che il compilatore C# aveva deciso di non emettere i metadati Constant.Poi l'output sarà:

C: IsLiteral = False 
F: IsLiteral = False 

che è chiaramente errato rispetto al codice sorgente C#, perché ora entrambi i campi appaiono come non const.

Infine, diciamo che il compilatore C# aveva deciso di non emette alcun metadati per C a tutti (dal momento che "inline" il valore del campo in ogni caso):

F: IsLiteral = False 

Anche questo è corretto, dal momento che la riflessione non segnala più a lungo l'esistenza di un campo che è chiaramente presente nel codice sorgente C#. Almeno per me, sarebbe un buon momento per sollevare un sopracciglio.

Questi contro-esempi dovrebbero chiarire perché è positivo che vengano emessi metadati completi anche per i campi const.

+0

Grazie per il chiarimento. Avrei preferito se fossero gestiti in modo simile a C++ #defines come nei campi non proprio reali, non essendo stati compilati, e la riflessione non li restituiva ma suppongo che i progettisti volessero che il supporto per la riflessione;) – stfx

Problemi correlati