在哪里可以了解 VS 调试器的“魔术名称”

Posted

技术标签:

【中文标题】在哪里可以了解 VS 调试器的“魔术名称”【英文标题】:Where to learn about VS debugger 'magic names' 【发布时间】:2011-01-31 07:37:11 【问题描述】:

如果您曾经使用过 Reflector,您可能会注意到 C# 编译器生成的类型、方法、字段和局部变量值得调试器“特殊”显示。例如,以“CS$”开头的局部变量不会显示给用户。对于匿名方法的闭包类型、自动属性的支持字段等还有其他特殊的命名约定。

我的问题:在哪里可以了解这些命名约定?有人知道一些文档吗?

我的目标是让 PostSharp 2.0 使用相同的约定。

【问题讨论】:

【参考方案1】:

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

但是,由于我是个好人,以下是其中的一些细节:

如果优化器删除了未使用的局部变量,我们无论如何都会将调试信息发送到 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 是描述性后缀(“当前”、“状态”等),因此您在读取元数据时不必记住上面的表格。 I 是可选的唯一编号

【讨论】:

谢谢!我会看看我是否可以让 PostSharp 闭包类的行为与 C# 编译器生成的一样好! @SLaks:与短暂的临时相反。持久临时变量本质上是没有名称的局部变量;它们在堆栈上有一个特定位置,该位置在堆栈帧的整个生命周期内都存在。短暂的临时对象只是在需要存储时被压入堆栈,然后在不再需要时弹出。持久的临时对象更容易调试,但可以使临时对象的生命周期更长。当优化关闭时,我们会生成持久的临时对象。 我有一个类似于闭包类的概念,但我没有将提升参数作为字段,而是将它们作为局部变量。这对于参数非常有效,但是如何告诉调试器“this”不是“ldarg.0”而是索引为 4 的局部变量?有什么神奇的名字吗? @Eric - 你能用 C# 5.0 (async/await) 生成的名称更新这个响应吗?我看到了一些新的前缀 :)

以上是关于在哪里可以了解 VS 调试器的“魔术名称”的主要内容,如果未能解决你的问题,请参考以下文章

调试信息(断点等)存储在 VS2013、本机 C++ dll 项目中的位置在哪里?

继续分享 5 个实用的 vs 调试技巧

VS2015 UCRT源文件在哪里?

关于VS调试

VS 2022 .NET 6.0“调试时总是启动”

调试时,数据存储在哪里