Lingkungan: Visual Studio 2015 RTM. (Saya belum mencoba versi yang lebih lama.)
Baru-baru ini, saya telah men-debug beberapa kode Waktu Noda saya , dan saya perhatikan bahwa ketika saya mendapatkan variabel jenis lokal NodaTime.Instant
(salah satu struct
jenis utama dalam Waktu Noda), jendela "Lokal" dan "Tonton" tampaknya tidak memanggil ToString()
penggantiannya. Jika saya menelepon ToString()
secara eksplisit di jendela arloji, saya melihat representasi yang sesuai, tetapi sebaliknya saya hanya melihat:
variableName {NodaTime.Instant}
yang sangat tidak berguna.
Jika saya mengubah override untuk mengembalikan string konstan, string yang ditampilkan dalam debugger, sehingga jelas mampu mengambil bahwa itu ada - itu hanya tidak ingin menggunakannya dalam state "normal".
Saya memutuskan untuk mereproduksi ini secara lokal di aplikasi demo kecil, dan inilah yang saya buat. (Perhatikan bahwa dalam versi awal posting ini, DemoStruct
adalah sebuah kelas dan DemoClass
tidak ada sama sekali - salahku, tapi itu menjelaskan beberapa komentar yang terlihat aneh sekarang ...)
using System;
using System.Diagnostics;
using System.Threading;
public struct DemoStruct
{
public string Name { get; }
public DemoStruct(string name)
{
Name = name;
}
public override string ToString()
{
Thread.Sleep(1000); // Vary this to see different results
return $"Struct: {Name}";
}
}
public class DemoClass
{
public string Name { get; }
public DemoClass(string name)
{
Name = name;
}
public override string ToString()
{
Thread.Sleep(1000); // Vary this to see different results
return $"Class: {Name}";
}
}
public class Program
{
static void Main()
{
var demoClass = new DemoClass("Foo");
var demoStruct = new DemoStruct("Bar");
Debugger.Break();
}
}
Di debugger, sekarang saya melihat:
demoClass {DemoClass}
demoStruct {Struct: Bar}
Namun, jika saya mengurangi Thread.Sleep
panggilan turun dari 1 detik menjadi 900 ms, masih ada jeda singkat, tetapi kemudian saya melihat Class: Foo
sebagai nilainya. Tampaknya tidak masalah berapa lama Thread.Sleep
panggilan itu masuk DemoStruct.ToString()
, selalu ditampilkan dengan benar - dan debugger menampilkan nilai sebelum tidur selesai. (Seolah-olah Thread.Sleep
dinonaktifkan.)
Sekarang Instant.ToString()
di Noda Time melakukan cukup banyak pekerjaan, tetapi tentu saja tidak memakan waktu satu detik - jadi mungkin ada lebih banyak kondisi yang menyebabkan debugger menyerah mengevaluasi ToString()
panggilan. Dan tentu saja itu adalah struct.
Saya sudah mencoba berulang-ulang untuk melihat apakah itu batas tumpukan, tetapi tampaknya tidak demikian.
Jadi, bagaimana saya bisa mengetahui apa yang menghentikan VS dari sepenuhnya mengevaluasi Instant.ToString()
? Seperti disebutkan di bawah ini, DebuggerDisplayAttribute
tampaknya membantu, tetapi tanpa tahu mengapa , saya tidak akan pernah sepenuhnya percaya diri ketika saya membutuhkannya dan ketika saya tidak.
Memperbarui
Jika saya gunakan DebuggerDisplayAttribute
, semuanya berubah:
// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass
memberi saya:
demoClass Evaluation timed out
Sedangkan ketika saya menerapkannya dalam Noda Time:
[DebuggerDisplay("{ToString()}")]
public struct Instant
aplikasi tes sederhana menunjukkan kepada saya hasil yang tepat:
instant "1970-01-01T00:00:00Z"
Jadi mungkin masalah di Noda Waktu adalah beberapa kondisi yang DebuggerDisplayAttribute
tidak berlaku melalui - meskipun tidak memaksa melalui timeout. (Ini akan sesuai dengan harapan saya yang Instant.ToString
cukup cepat untuk menghindari batas waktu.)
Ini mungkin solusi yang cukup bagus - tetapi saya masih ingin tahu apa yang terjadi, dan apakah saya dapat mengubah kode hanya untuk menghindari keharusan meletakkan atribut pada semua jenis nilai yang berbeda di Noda Time.
Ingin tahu dan ingin tahu
Apa pun yang membingungkan, debugger terkadang hanya membingungkannya. Mari kita membuat sebuah kelas yang memegang sebuah Instant
dan menggunakannya untuk sendiri ToString()
metode:
using NodaTime;
using System.Diagnostics;
public class InstantWrapper
{
private readonly Instant instant;
public InstantWrapper(Instant instant)
{
this.instant = instant;
}
public override string ToString() => instant.ToString();
}
public class Program
{
static void Main()
{
var instant = NodaConstants.UnixEpoch;
var wrapper = new InstantWrapper(instant);
Debugger.Break();
}
}
Sekarang saya akhirnya melihat:
instant {NodaTime.Instant}
wrapper {1970-01-01T00:00:00Z}
Namun, atas saran Eren dalam komentar, jika saya berubah InstantWrapper
menjadi seorang struct, saya mendapatkan:
instant {NodaTime.Instant}
wrapper {InstantWrapper}
Sehingga dapat mengevaluasi Instant.ToString()
- selama itu dipanggil oleh ToString
metode lain ... yang ada di dalam kelas. Bagian kelas / struct tampaknya penting berdasarkan pada jenis variabel yang ditampilkan, bukan kode apa yang perlu dieksekusi untuk mendapatkan hasilnya.
Sebagai contoh lain dari ini, jika kita menggunakan:
object boxed = NodaConstants.UnixEpoch;
... lalu berfungsi dengan baik, menampilkan nilai yang tepat. Warna saya bingung.
DebuggerDisplayAttribute
akan menyebabkannya mencoba sedikit lebih keras.