Wo Sie mehr über die magischen Namen des VS-Debuggers erfahren können

110

Wenn Sie jemals Reflector verwendet haben, haben Sie wahrscheinlich bemerkt, dass der C # -Compiler Typen, Methoden, Felder und lokale Variablen generiert, die vom Debugger eine spezielle Anzeige verdienen. Beispielsweise werden lokale Variablen, die mit 'CS $' beginnen, dem Benutzer nicht angezeigt. Es gibt andere spezielle Namenskonventionen für Schließungstypen anonymer Methoden, Sicherungsfelder für automatische Eigenschaften usw.

Meine Frage: Wo kann man etwas über diese Namenskonventionen erfahren? Kennt jemand eine Dokumentation?

Mein Ziel ist es, PostSharp 2.0 dazu zu bringen, dieselben Konventionen zu verwenden.

Gael Fraiteur
quelle

Antworten:

209

Dies sind undokumentierte Implementierungsdetails des Compilers, die jederzeit geändert werden können. (UPDATE: GeneratedNames.cs Die aktuellen Details finden Sie in den C # -Quellen. Die folgende Beschreibung ist etwas veraltet.)

Da ich jedoch ein netter Kerl bin, sind hier einige dieser Details:

Wenn Sie eine nicht verwendete lokale Variable haben, die der Optimierer entfernt, geben wir trotzdem Debug-Informationen dafür in den PDB aus. Wir haben das Suffix __Deleted$auf solche Variablen geklebt , damit der Debugger weiß, dass sie im Quellcode enthalten, aber nicht in der Binärdatei dargestellt sind.

Vom Compiler zugewiesene temporäre Variablen-Slots erhalten Namen mit dem Muster CS $ X $ Y, wobei X die "temporäre Art" und Y die Anzahl der bisher zugewiesenen temporären Slots ist. Die vorübergehenden Arten sind:

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.  

Temporäre Arten zwischen 8 und 264 sind zusätzliche Array-Indexspeicher für mehrdimensionale Arrays.

Temporäre Arten über 264 werden für temporäre Arten verwendet, bei denen die feste Anweisung eine Zeichenfolge fixiert.

Spezielle vom Compiler generierte Namen werden generiert für:

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")

Das Muster zum Generieren magischer Namen lautet: P<N>C__SIwo:

  • P ist CS $ für zwischengespeicherte Delegaten und Anzeigeklasseninstanzen, ansonsten leer.
  • N ist der ursprüngliche Name, der mit der Sache verbunden ist, falls vorhanden
  • C ist das oben aufgeführte Zeichen 1 bis s
  • S ist ein beschreibendes Suffix ("aktuell", "Status" usw.), damit Sie sich beim Lesen der Metadaten nicht die obige Tabelle merken müssen.
  • Ich bin eine optionale eindeutige Nummer
Eric Lippert
quelle
2
Danke dir! Ich werde sehen, ob ich PostSharp-Abschlussklassen so gut verhalten kann, wie es der C # -Compiler generiert!
Gael Fraiteur
7
@SLaks: Das Gegenteil einer kurzlebigen temporären. Dauerhafte Provisorien sind im Wesentlichen lokale Variablen ohne Namen. Sie haben eine bestimmte Position auf dem Stapel, die für die Lebensdauer des Stapelrahmens gültig ist. Kurzlebige Provisorien werden nur dann auf den Stapel geschoben, wenn ihr Speicher benötigt wird, und dann abgesprungen, wenn sie nicht mehr benötigt werden. Dauerhafte Provisorien sind viel einfacher zu debuggen, können jedoch die Lebensdauer von Provisorien erheblich verlängern. Wir generieren dauerhafte Provisorien, wenn die Optimierungen deaktiviert sind.
Eric Lippert
Ich habe ein ähnliches Konzept wie Abschlussklassen, aber anstatt Parameter als Felder anzuheben, habe ich sie als lokale Variablen. Dies funktioniert ziemlich gut für Parameter, aber wie kann man dem Debugger sagen, dass 'this' nicht 'ldarg.0' ist, sondern die lokale Variable mit Index 4? Gibt es einen magischen Namen?
Gael Fraiteur
23
@Eric - Könnten Sie diese Antwort mit Namen aktualisieren, die von C # 5.0 generiert wurden (async / await)? Ich habe einige neue Präfixe gesehen :)
Gael Fraiteur