Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
DebuggerDisplayAttribute mengontrol bagaimana objek, properti, atau bidang ditampilkan di jendela variabel debugger. Atribut ini dapat diterapkan ke jenis (kelas, struktur, enum, delegasi), tetapi biasanya hanya diterapkan ke kelas dan struktur. Jika diterapkan ke jenis dasar, atribut juga berlaku untuk subkelas.
Atribut DebuggerDisplay memiliki argumen tunggal, yang merupakan string yang akan ditampilkan di kolom nilai untuk instans jenis. String ini dapat berisi kurung kurawal ({ dan }). Teks dalam sepasang kurung kurawal dievaluasi sebagai bidang, properti, atau metode.
Jika kelas memiliki metode ToString() yang di-overrides, debugger menggunakan metode yang di-overrides alih-alih {<typeName>}default. Dalam hal ini Anda tidak perlu menggunakan DebuggerDisplay. Jika Anda menggunakan keduanya, atribut DebuggerDisplay diprioritaskan daripada metode ToString() yang diatur ulang. Atribut DebuggerDisplay juga lebih diutamakan daripada metode ToString() yang ditimpa dalam subkelas.
Apakah debugger mengevaluasi panggilan implisit ToString() ini bergantung pada opsi Penelusuran Kesalahan di bawah Alat (atau Debug) >Opsi.
Important
Jika Anda memilih opsi Tampilkan struktur mentah objek dalam jendela variabel , DebuggerDisplay atribut diabaikan. Pengaturan ini terletak di panelOpsi> di bagian Semua Pengaturan>Debugging>Umum.
Important
Jika Anda memilih opsi Tampilkan struktur mentah objek dalam jendela variabel , DebuggerDisplay atribut diabaikan. Pengaturan ini terletak di dialogOpsi> di bagian Men-debug>Umum.
Note
Untuk kode asli, atribut ini hanya didukung dalam kode C++/CLI.
Tabel berikut menunjukkan beberapa kemungkinan penggunaan atribut DebuggerDisplay dan contoh output.
| Attribute | Keluaran yang muncul di kolom Nilai |
|---|---|
[DebuggerDisplay("x = {x} y = {y}")]Digunakan pada tipe dengan bidang x dan y. |
x = 5 y = 18 |
[DebuggerDisplay("String value is {getString()}")]Sintaks parameter dapat bervariasi di antara bahasa. Oleh karena itu, gunakan dengan hati-hati. |
String value is [5, 6, 6] |
DebuggerDisplay juga dapat menerima parameter yang diberi nama.
| Parameters | Purpose |
|---|---|
Name, Type |
Parameter-parameter ini memengaruhi kolom Nama dan Jenis dari jendela variabel. (Mereka dapat diatur ke string menggunakan sintaks yang sama dengan konstruktor.) Menggunakan parameter ini secara berlebihan, atau menggunakannya dengan tidak benar, dapat menyebabkan output yang membingungkan. |
Target, TargetTypeName |
Menentukan jenis target saat atribut digunakan pada tingkat perakitan. |
File autoexp.cs menggunakan atribut DebuggerDisplay di tingkat perakitan. File autoexp.cs menentukan ekspansi default yang digunakan Visual Studio untuk objek .NET. Anda dapat memeriksa file autoexp.cs untuk contoh cara menggunakan atribut DebuggerDisplay, atau Anda dapat memodifikasi dan mengkompilasi file autoexp.cs untuk mengubah ekspansi default. Pastikan untuk mencadangkan file autoexp.cs sebelum Anda mengubahnya.
Untuk membangun autoexp.cs, buka Perintah Pengembang untuk VS2015, dan jalankan perintah berikut
cd <directory containing autoexp.cs>
csc /t:library autoexp.cs
Perubahan padaautoexp.dll akan diambil di sesi debug berikutnya.
Menggunakan Ekspresi di DebuggerDisplay
Meskipun Anda dapat menggunakan ekspresi umum antara kurung kurawal dalam atribut DebuggerDisplay, praktik ini tidak disarankan.
Ekspresi umum dalam DebuggerDisplay memiliki akses implisit ke pointer this untuk instans saat ini dari jenis target saja. Ekspresi tidak memiliki akses ke alias, lokal, atau pointer. Jika ekspresi mereferensikan properti, atribut pada properti tersebut tidak diproses. Misalnya, kode C# [DebuggerDisplay("Object {count - 2}")] akan ditampilkan Object 6 jika bidang count adalah 8.
Menggunakan ekspresi di DebuggerDisplay dapat menyebabkan masalah berikut:
Mengevaluasi ekspresi adalah operasi termahal dalam debugger dan ekspresi dievaluasi setiap kali ditampilkan. Ini dapat menyebabkan masalah performa dalam melangkah melalui kode. Misalnya, ekspresi kompleks yang digunakan untuk menampilkan nilai dalam koleksi atau daftar bisa sangat lambat ketika jumlah elemen besar.
Ekspresi dievaluasi oleh evaluator ekspresi dari bahasa pada bingkai tumpukan saat ini dan bukan oleh evaluator dari bahasa di mana ekspresi tersebut ditulis. Ini dapat menyebabkan hasil yang tidak dapat diprediksi ketika bahasa berbeda.
Mengevaluasi ekspresi dapat mengubah status aplikasi. Misalnya, ekspresi yang mengatur nilai properti mengubah nilai properti tersebut dalam kode yang dijalankan.
Salah satu cara untuk mengurangi kemungkinan masalah evaluasi ekspresi adalah dengan membuat properti privat yang melakukan operasi dan mengembalikan string. Atribut DebuggerDisplay kemudian dapat menampilkan nilai properti privat tersebut. Contoh berikut mengimplementasikan pola ini:
[DebuggerDisplay("{DebuggerDisplay,nq}")]
public sealed class MyClass
{
public int count { get; set; }
public bool flag { get; set; }
private string DebuggerDisplay
{
get
{
return string.Format("Object {0}", count - 2);
}
}
}
Akhiran ",nq" memberi tahu evaluator ekspresi untuk menghapus tanda kutip saat menampilkan nilai akhir (nq = tanpa tanda kutip). Untuk informasi selengkapnya tentang pemformat, lihat Penentu format di C#.
Example
Contoh kode berikut menunjukkan cara menggunakan DebuggerDisplay, bersama dengan DebuggerBrowsable dan DebuggerTypeProxy. Saat dilihat di jendela variabel debugger, seperti jendela Watch, jendela menghasilkan ekspansi yang terlihat seperti ini:
| Name | Value | Type |
|---|---|---|
| Key | "three" | objek {string} |
| Value | 3 | objek {int} |
[DebuggerDisplay("{value}", Name = "{key}")]
internal class KeyValuePairs
{
private IDictionary dictionary;
private object key;
private object value;
public KeyValuePairs(IDictionary dictionary, object key, object value)
{
this.value = value;
this.key = key;
this.dictionary = dictionary;
}
public object Key
{
get { return key; }
set
{
object tempValue = dictionary[key];
dictionary.Remove(key);
key = value;
dictionary.Add(key, tempValue);
}
}
public object Value
{
get { return this.value; }
set
{
this.value = value;
dictionary[key] = this.value;
}
}
}
[DebuggerDisplay("{DebuggerDisplay,nq}")]
[DebuggerTypeProxy(typeof(HashtableDebugView))]
class MyHashtable
{
public Hashtable hashtable;
public MyHashtable()
{
hashtable = new Hashtable();
}
private string DebuggerDisplay { get { return "Count = " + hashtable.Count; } }
private class HashtableDebugView
{
private MyHashtable myhashtable;
public HashtableDebugView(MyHashtable myhashtable)
{
this.myhashtable = myhashtable;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePairs[] Keys
{
get
{
KeyValuePairs[] keys = new KeyValuePairs[myhashtable.hashtable.Count];
int i = 0;
foreach (object key in myhashtable.hashtable.Keys)
{
keys[i] = new KeyValuePairs(myhashtable.hashtable, key, myhashtable.hashtable[key]);
i++;
}
return keys;
}
}
}
}