如何学习关于 VS 调试器的“魔法名称”?

119
如果您曾使用Reflector,那么您可能会注意到C#编译器生成的类型、方法、字段和局部变量,值得由调试器进行“特殊”显示。例如,以“CS $”开头的局部变量不会显示给用户。对于匿名方法的闭包类型,自动属性的后备字段等,还有其他特殊的命名约定。
我的问题是:在哪里可以了解这些命名约定?是否有人知道一些相关的文档?
我的目标是使PostSharp 2.0使用相同的约定。
1个回答

220

这些是编译器未记录的实现细节,随时可能会更改。(更新:请参见C#源代码中的GeneratedNames.cs以获取当前的详细信息;下面的描述有些过时。)

然而,既然我是个好人,就给你一些细节:

如果您有一个未使用的本地变量,优化器会将其删除,但我们仍然会将调试信息发射到PDB中。对于这种变量,我们在后缀上添加了__Deleted$,以便调试器知道它们在源代码中存在,但在二进制文件中未被表示。

编译器分配的临时变量插槽使用模式CS$X$Y进行命名,其中X为“临时类型”,Y为迄今为止分配的临时变量数。临时类型包括:

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.  

8到264之间的临时类型是用于多维数组的附加索引存储。

264以上的临时类型用于涉及固定语句修复字符串的临时变量。

特殊的编译器生成名称用于:

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

生成神奇名称的模式为:P<N>C__SI,其中:

  • P对于缓存委托和显示类实例是CS$,否则为空。
  • N是与该对象关联的原始名称(如果有)
  • C是上面列出的1到s个字符之一
  • S是一个描述性后缀(如“current”,“state”等),这样在读取元数据时无需记住上面的表格。
  • I是可选的唯一编号

2
谢谢您!我会尽力让PostSharp闭包类的表现和C#编译器生成的一样好! - Gael Fraiteur
7
持久暂存变量是短暂暂存变量的反义词。它们本质上是没有名称的局部变量,在栈上有特定的位置,其生命周期与栈帧相同。当需要它们的存储空间时,短暂暂存变量会被推到栈上,不再需要时则弹出。持久暂存变量更易于调试,但可能使暂存变量的寿命更长。当关闭优化时,我们会生成持久暂存变量。 - Eric Lippert
我有一个类似闭包类的概念,但是与其将提升的参数作为字段不同,我将它们作为局部变量。对于参数来说,这个方法非常有效,但是如何告诉调试器,'this'不是'ldarg.0'而是索引为4的局部变量?有什么神奇的名称吗? - Gael Fraiteur
25
@Eric - 你能否使用C# 5.0生成的名称更新此响应(包括async/await)?我见过一些新的前缀 :) - Gael Fraiteur

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接