Dove trovare informazioni sui "nomi magici" del debugger VS


110

Se hai mai usato Reflector, probabilmente hai notato che il compilatore C # genera tipi, metodi, campi e variabili locali, che meritano una visualizzazione "speciale" da parte del debugger. Ad esempio, le variabili locali che iniziano con "CS $" non vengono visualizzate all'utente. Esistono altre convenzioni di denominazione speciali per i tipi di chiusura di metodi anonimi, campi di supporto di proprietà automatiche e così via.

La mia domanda: dove imparare a conoscere queste convenzioni di denominazione? Qualcuno sa di documentazione?

Il mio obiettivo è fare in modo che PostSharp 2.0 utilizzi le stesse convenzioni.

Risposte:


209

Questi sono dettagli di implementazione non documentati del compilatore e soggetti a modifiche in qualsiasi momento. (AGGIORNAMENTO: vedere GeneratedNames.cs nelle fonti C # per i dettagli correnti; la descrizione di seguito è un po 'obsoleta.)

Tuttavia, dato che sono un bravo ragazzo, ecco alcuni di quei dettagli:

Se hai una variabile locale inutilizzata che l'ottimizzatore rimuove, emettiamo comunque le informazioni di debug per essa nel PDB. Abbiamo applicato il suffisso __Deleted$a tali variabili in modo che il debugger sappia che erano nel codice sorgente ma non rappresentate nel binario.

Agli slot di variabili temporanee allocati dal compilatore vengono assegnati nomi con il pattern CS $ X $ Y, dove X è il "tipo temporaneo" e Y è il numero di temporanei assegnati finora. I tipi temporanei sono:

0 --> short lived temporaries
1 --> return value temporaries
2 --> temporaries generated for lock statements
3 --> temporaries generated for using statements
4 --> durable temporaries
5 --> the result of get enumerator in a foreach
6 --> the array storage in a foreach
7 --> the array index storage in a foreach.  

I tipi temporanei tra 8 e 264 sono archivi di indici di array aggiuntivi per array multidimensionali.

I tipi temporanei sopra 264 sono usati per i provvisori che coinvolgono l'istruzione fissa che fissa una stringa.

Vengono generati nomi speciali generati dal compilatore per:

1 --> the iterator state ("state")
2 --> the value of current in an iterator ("current")
3 --> a saved parameter in an iterator
4 --> a hoisted 'this' in an iterator ("this")
5 --> a hoisted local in an iterator
6 --> the hoisted locals from an outer scope
7 --> a hoisted wrapped value ("wrap")
8 --> the closure class instance ("locals")
9 --> the cached delegate instance ("CachedAnonymousMethodDelegate")
a --> the iterator instance ("iterator")
b --> an anonymous method
c --> anonymous method closure class ("DisplayClass")
d --> iterator class
e --> fixed buffer struct ("FixedBuffer")
f --> anonymous type ("AnonymousType")
g --> initializer local ("initLocal")
h --> query expression temporary ("TransparentIdentifier")
i --> anonymous type field ("Field")
j --> anonymous type type parameter ("TPar")
k --> auto prop field ("BackingField")
l --> iterator thread id
m --> iterator finally ("Finally")
n --> fabricated method ("FabricatedMethod")
o --> dynamic container class ("SiteContainer")
p --> dynamic call site ("Site")
q --> dynamic delegate ("SiteDelegate")
r --> com ref call local ("ComRefCallLocal")
s --> lock taken local ("LockTaken")

Lo schema per generare nomi magici è: P<N>C__SIdove:

  • P è CS $ per i delegati memorizzati nella cache e le istanze di classi di visualizzazione, altrimenti vuoto.
  • N è il nome originale associato all'oggetto, se esiste
  • C è il carattere da 1 a s sopra elencati
  • S è un suffisso descrittivo ("corrente", "stato" e così via) in modo da non dover memorizzare la tabella sopra durante la lettura dei metadati.
  • I è un numero univoco opzionale

2
Grazie! Vedrò se riesco a fare in modo che le classi di chiusura PostSharp si comportino bene come ciò che genera il compilatore C #!
Gael Fraiteur

7
@SLaks: l'opposto di un temporaneo di breve durata. I provvisori durevoli sono essenzialmente variabili locali senza nome; hanno una posizione specifica nello stack che vive per la durata dello stack frame. I provvisori di breve durata vengono semplicemente messi in pila quando è necessario il loro stoccaggio e quindi rimossi quando non sono più necessari. I provvisori durevoli sono molto più facili da eseguire il debug, ma possono allungare la durata dei provvisori. Generiamo provvisori durevoli quando le ottimizzazioni sono disattivate.
Eric Lippert

Ho un concetto simile alle classi di chiusura, ma invece di avere parametri issati come campi, li ho come variabili locali. Questo funziona abbastanza bene per i parametri, ma come dire al debugger che 'questo' non è 'ldarg.0' ma la variabile locale con indice 4? C'è qualche nome magico?
Gael Fraiteur

23
@Eric - potresti aggiornare questa risposta con i nomi generati da C # 5.0 (async / await)? Ho visto alcuni nuovi prefissi :)
Gael Fraiteur
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.