Onde aprender sobre os 'nomes mágicos' do depurador VS

110

Se você já usou o Reflector, provavelmente notou que o compilador C # gera tipos, métodos, campos e variáveis ​​locais que merecem exibição 'especial' pelo depurador. Por exemplo, variáveis ​​locais começando com 'CS $' não são exibidas para o usuário. Existem outras convenções de nomenclatura especiais para tipos de fechamento de métodos anônimos, campos de apoio de propriedades automáticas e assim por diante.

Minha pergunta: onde aprender sobre essas convenções de nomenclatura? Alguém conhece alguma documentação?

Meu objetivo é fazer o PostSharp 2.0 usar as mesmas convenções.

Gael Fraiteur
fonte

Respostas:

209

Esses são detalhes de implementação não documentados do compilador e estão sujeitos a alterações a qualquer momento. (ATUALIZAÇÃO: Veja GeneratedNames.cs nas fontes C # os detalhes atuais; a descrição abaixo está um tanto desatualizada.)

No entanto, como sou um cara legal, aqui estão alguns desses detalhes:

Se você tiver uma variável local não utilizada que o otimizador remove, emitimos informações de depuração para ela de qualquer maneira no PDB. Colocamos o sufixo __Deleted$nessas variáveis ​​para que o depurador saiba que elas estavam no código-fonte, mas não representadas no binário.

Os slots de variáveis ​​temporárias alocados pelo compilador recebem nomes com o padrão CS $ X $ Y, onde X é o "tipo temporário" e Y é o número de temporários alocados até agora. Os tipos temporários são:

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.  

Tipos temporários entre 8 e 264 são armazenamentos de índice de matriz adicionais para matrizes multidimensionais.

Tipos temporários acima de 264 são usados ​​para temporários envolvendo a instrução fixa que fixa uma corda.

Nomes especiais gerados pelo compilador são gerados para:

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

O padrão para gerar nomes mágicos é: P<N>C__SIonde:

  • P é CS $ para delegados em cache e instâncias de classe de exibição; caso contrário, vazio.
  • N é o nome original associado à coisa, se houver
  • C é o caractere de 1 a s listado acima
  • S é um sufixo descritivo ("atual", "estado" e assim por diante) para que você não precise ter a tabela acima memorizada ao ler os metadados.
  • I é um número opcional exclusivo
Eric Lippert
fonte
2
Obrigado! Vou ver se consigo fazer as classes de encerramento PostSharp se comportarem tão bem quanto o que o compilador C # gera!
Gael Fraiteur
7
@SLaks: O oposto de um temporário de curta duração. Temporários duráveis ​​são essencialmente variáveis ​​locais sem nomes; eles têm um local específico na pilha que dura toda a vida útil do quadro de pilha. Os provisórios de curta duração são simplesmente colocados na pilha quando seu armazenamento é necessário e, em seguida, retirados quando não é mais necessário. Os temporários duráveis ​​são muito mais fáceis de depurar, mas podem tornar a vida útil dos temporários muito mais longa. Geramos temporários duráveis ​​quando as otimizações estão desligadas.
Eric Lippert
Eu tenho um conceito semelhante a classes de fechamento, mas em vez de ter os parâmetros içados como campos, eu os tenho como variáveis ​​locais. Isso funciona muito bem para parâmetros, mas como dizer ao depurador que 'this' não é 'ldarg.0', mas a variável local com índice 4? Existe algum nome mágico?
Gael Fraiteur
23
@Eric - você poderia atualizar esta resposta com nomes gerados pelo C # 5.0 (async / await)? Eu vi alguns novos prefixos :)
Gael Fraiteur