Tempat belajar tentang 'nama ajaib' VS debugger

110

Jika Anda pernah menggunakan Reflector, Anda mungkin memperhatikan bahwa kompilator C # menghasilkan tipe, metode, bidang, dan variabel lokal, yang pantas ditampilkan 'khusus' oleh debugger. Misalnya, variabel lokal yang diawali dengan 'CS $' tidak ditampilkan kepada pengguna. Ada konvensi penamaan khusus lainnya untuk tipe penutupan metode anonim, bidang pendukung properti otomatis, dan sebagainya.

Pertanyaan saya: di mana bisa belajar tentang konvensi penamaan ini? Adakah yang tahu tentang beberapa dokumentasi?

Tujuan saya adalah membuat PostSharp 2.0 menggunakan konvensi yang sama.

Gael Fraiteur
sumber

Jawaban:

209

Ini adalah detail implementasi compiler yang tidak berdokumen, dan dapat berubah sewaktu-waktu. (PEMBARUAN: Lihat GeneratedNames.cs di sumber C # untuk detail saat ini; deskripsi di bawah ini agak ketinggalan zaman.)

Namun, karena saya pria yang baik, berikut beberapa detailnya:

Jika Anda memiliki variabel lokal yang tidak digunakan yang dihapus pengoptimal, kami tetap mengirimkan info debug untuk variabel tersebut ke PDB. Kami menempelkan sufiks __Deleted$ke variabel tersebut sehingga debugger tahu bahwa mereka ada dalam kode sumber tetapi tidak terwakili dalam biner.

Slot variabel sementara yang dialokasikan oleh kompilator diberi nama dengan pola CS $ X $ Y, di mana X adalah "jenis sementara" dan Y adalah jumlah temporer yang dialokasikan sejauh ini. Jenis sementara adalah:

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.  

Jenis sementara antara 8 dan 264 adalah penyimpanan indeks array tambahan untuk array multidimensi.

Jenis sementara di atas 264 digunakan untuk temporer yang melibatkan pernyataan tetap yang mengikatkan sebuah string.

Nama khusus yang dibuat oleh kompilator dibuat untuk:

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

Pola untuk menghasilkan nama magis adalah: P<N>C__SIdimana:

  • P adalah CS $ untuk delegasi yang di-cache dan menampilkan instance kelas, jika tidak kosongkan.
  • N adalah nama asli yang diasosiasikan dengan benda itu, jika ada
  • C adalah karakter 1 sampai s yang tercantum di atas
  • S adalah sufiks deskriptif ("saat ini", "status", dan seterusnya) sehingga Anda tidak perlu mengingat tabel di atas saat membaca metadata.
  • I adalah nomor unik opsional
Eric Lippert
sumber
2
Terima kasih! Saya akan melihat apakah saya dapat membuat kelas penutupan PostSharp berperilaku sebaik apa yang dihasilkan kompilator C #!
Gael Fraiteur
7
@SLaks: Kebalikan dari sementara yang berumur pendek. Temporer yang tahan lama pada dasarnya adalah variabel lokal tanpa nama; mereka memiliki lokasi tertentu di tumpukan yang berlaku selama masa pakai bingkai tumpukan. Temporer yang berumur pendek hanya didorong ke tumpukan saat penyimpanannya dibutuhkan dan kemudian muncul saat tidak lagi diperlukan. Temporer yang tahan lama jauh lebih mudah untuk di-debug, tetapi dapat membuat masa pakai sementara lebih lama. Kami menghasilkan temporer yang tahan lama saat pengoptimalan dinonaktifkan.
Eric Lippert
Saya memiliki konsep yang mirip dengan kelas penutupan, tetapi alih-alih memiliki parameter yang diangkat sebagai bidang, saya menjadikannya sebagai variabel lokal. Ini berfungsi cukup baik untuk parameter, tetapi bagaimana cara memberi tahu debugger bahwa 'this' bukan 'ldarg.0' tetapi variabel lokal dengan indeks 4? Apakah ada nama ajaib?
Gael Fraiteur
23
@Eric - dapatkah Anda memperbarui tanggapan ini dengan nama yang dihasilkan oleh C # 5.0 (async / await)? Saya telah melihat beberapa awalan baru :)
Gael Fraiteur