Where to learn about VS debugger 'magic names'
Asked Answered
D

1

119

If you've ever used Reflector, you probably noticed that the C# compiler generates types, methods, fields, and local variables, that deserve 'special' display by the debugger. For instance, local variables beginning with 'CS$' are not displayed to the user. There are other special naming conventions for closure types of anonymous methods, backing fields of automatic properties, and so on.

My question: where to learn about these naming conventions? Does anyone know about some documentation?

My objective is to make PostSharp 2.0 use the same conventions.

Deuce answered 24/3, 2010 at 15:12 Comment(0)
C
221

These are undocumented implementation details of the compiler, and subject to change at any time. (UPDATE: See GeneratedNames.cs in the C# sources for the current details; the description below is somewhat out-of-date.)

However, since I'm a nice guy, here are some of those details:

If you have an unused local variable that the optimizer removes, we emit debug info for it anyway into the PDB. We stuck the suffix __Deleted$ onto such variables so that the debugger knows that they were in source code but not represented in the binary.

Temporary variable slots allocated by the compiler are given names with the pattern CS$X$Y, where X is the "temporary kind" and Y is the number of temporaries allocated so far. The temporary kinds are:

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.  

Temporary kinds between 8 and 264 are additional array index storages for multidimensional arrays.

Temporary kinds above 264 are used for temporaries involving the fixed statement fixing a string.

Special compiler-generated names are generated for:

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

The pattern for generating magical names is: P<N>C__SI where:

  • P is CS$ for cached delegates and display class instances, empty otherwise.
  • N is the original name associated with the thing, if any
  • C is the character 1 through s listed above
  • S is a descriptive suffix ("current", "state", and so on) so that you don't have to have the table above memorized when reading the metadata.
  • I is an optional unique number
Concettaconcettina answered 24/3, 2010 at 16:37 Comment(4)
Thank you! I'll see if I can make PostSharp closure classes behave as nicely as what the C# compiler generates!Deuce
@SLaks: The opposite of a short-lived temporary. Durable temporaries are essentially local variables without names; they have a specific location on the stack that lives for the lifetime of the stack frame. Short-lived temporaries are just pushed on the stack when their storage is needed and then popped off when it is no longer needed. Durable temporaries are much easier to debug, but can make lifetimes of temporaries much longer. We generate durable temporaries when optimizations are off.Concettaconcettina
I have a concept similar to closure classes, but instead of having hoisted parameters as fields, I have them as local variables. This works pretty well for parameters, but how to tell the debugger that 'this' is not 'ldarg.0' but the local variable with index 4? Is there any magic name?Deuce
@Eric - could you update this response with names generated by C# 5.0 (async/await)? I've seen some new prefixes :)Deuce

© 2022 - 2024 — McMap. All rights reserved.