สภาพแวดล้อม: Visual Studio 2015 RTM (ฉันไม่ได้ลองรุ่นที่เก่ากว่า)
เมื่อเร็ว ๆ นี้ฉันได้ทำการดีบักรหัสเวลา Nodaของฉันและฉันสังเกตว่าเมื่อฉันมีตัวแปรประเภทท้องถิ่นNodaTime.Instant
(หนึ่งในstruct
ประเภทส่วนกลางในเวลา Noda) หน้าต่าง "คนในท้องถิ่น" และ "ดู" ดูเหมือนจะไม่เรียกใช้การToString()
แทนที่ หากฉันโทรToString()
อย่างชัดเจนในหน้าต่างดูฉันเห็นการแสดงที่เหมาะสม แต่ไม่เช่นนั้นฉันก็เห็น:
variableName {NodaTime.Instant}
ซึ่งไม่มีประโยชน์มาก
ถ้าฉันเปลี่ยนการแทนที่เพื่อส่งคืนสตริงคงที่สตริงนั้นจะปรากฏในดีบักเกอร์ดังนั้นจึงสามารถรับได้อย่างชัดเจนว่ามันอยู่ที่นั่น - มันไม่ต้องการใช้มันในสถานะ "ปกติ"
ฉันตัดสินใจที่จะทำซ้ำในประเทศนี้ในแอปตัวอย่างเล็ก ๆ น้อย ๆ และนี่คือสิ่งที่ฉันคิดขึ้นมา (โปรดทราบว่าในเวอร์ชันแรกของโพสต์DemoStruct
นี้เป็นคลาสและDemoClass
ไม่มีอยู่จริง - ความผิดของฉัน แต่มันอธิบายความคิดเห็นบางอย่างที่ดูแปลก ๆ ในตอนนี้ ... )
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();
}
}
ในดีบักเกอร์ตอนนี้ฉันเห็น:
demoClass {DemoClass}
demoStruct {Struct: Bar}
อย่างไรก็ตามหากฉันลดการThread.Sleep
โทรลงจาก 1 วินาทีถึง 900 มิลลิวินาทีก็ยังคงมีการหยุดชั่วคราว แต่ฉันเห็นClass: Foo
ว่าเป็นค่า ดูเหมือนว่าไม่สำคัญว่าจะมีการThread.Sleep
โทรติดต่อนานแค่ไหนDemoStruct.ToString()
และจะปรากฏขึ้นอย่างถูกต้องและดีบักเกอร์จะแสดงค่าก่อนที่โหมดสลีปจะเสร็จสิ้น (เหมือนว่าThread.Sleep
ปิดใช้งานอยู่)
ขณะนี้Instant.ToString()
ใน Noda Time มีปริมาณงานที่พอเหมาะ แต่ไม่ใช้เวลาสักวินาทีดังนั้นจึงมีเงื่อนไขเพิ่มเติมที่ทำให้ debugger ยกเลิกการประเมินผลการToString()
โทร และแน่นอนมันเป็นโครงสร้างอยู่แล้ว
ฉันลองเรียกดูซ้ำเพื่อดูว่าเป็นขีด จำกัด ของสแต็กหรือไม่ แต่ก็ไม่เป็นเช่นนั้น
ดังนั้นฉันจะทราบได้อย่างไรว่าอะไรจะหยุด VS Instant.ToString()
ไม่ให้ประเมินอย่างสมบูรณ์ ดังที่ระบุไว้ด้านล่างDebuggerDisplayAttribute
ดูเหมือนจะช่วย แต่โดยไม่รู้ว่าทำไมฉันไม่เคยจะมั่นใจในเมื่อฉันต้องการมันและเมื่อฉันไม่
ปรับปรุง
ถ้าฉันใช้DebuggerDisplayAttribute
สิ่งต่าง ๆ จะเปลี่ยนไป:
// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass
ให้ฉัน:
demoClass Evaluation timed out
โดยที่เมื่อฉันใช้ใน Noda Time:
[DebuggerDisplay("{ToString()}")]
public struct Instant
แอปทดสอบอย่างง่ายแสดงผลลัพธ์ที่ถูกต้อง:
instant "1970-01-01T00:00:00Z"
ดังนั้นคงจะมีปัญหาใน Noda เวลาเป็นเงื่อนไขบางอย่างที่DebuggerDisplayAttribute
ไม่แรงผ่าน - แม้ว่ามันจะไม่ได้บังคับให้ผ่านหมดเวลา (นี่จะเป็นไปตามความคาดหวังของฉันที่Instant.ToString
เร็วพอที่จะหลีกเลี่ยงการหมดเวลา)
นี่อาจเป็นทางออกที่ดีพอ - แต่ฉันยังอยากรู้ว่าเกิดอะไรขึ้นและฉันสามารถเปลี่ยนรหัสได้หรือไม่เพื่อหลีกเลี่ยงการใส่แอตทริบิวต์ในประเภทค่าต่างๆทั้งหมดใน Noda Time
อยากรู้อยากเห็นและอยากรู้อยากเห็น
อะไรก็ตามที่ทำให้ดีบั๊กสับสนในบางครั้งมันทำให้สับสน ลองสร้างชั้นซึ่งถือInstant
และใช้มันสำหรับของตัวเองToString()
วิธีการ:
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();
}
}
ตอนนี้ฉันเห็น:
instant {NodaTime.Instant}
wrapper {1970-01-01T00:00:00Z}
อย่างไรก็ตามตามคำแนะนำของ Eren ในความคิดเห็นหากฉันเปลี่ยนInstantWrapper
เป็น struct ฉันจะได้รับ:
instant {NodaTime.Instant}
wrapper {InstantWrapper}
ดังนั้นมันจึงสามารถประเมินได้Instant.ToString()
- ตราบใดที่มันถูกเรียกโดยToString
วิธีอื่น... ซึ่งอยู่ในชั้นเรียน ส่วนคลาส / โครงสร้างดูเหมือนจะมีความสำคัญโดยขึ้นอยู่กับประเภทของตัวแปรที่จะแสดงไม่ใช่รหัสที่ต้องใช้ในการประมวลผลเพื่อให้ได้ผลลัพธ์
เป็นอีกตัวอย่างหนึ่งของสิ่งนี้ถ้าเราใช้:
object boxed = NodaConstants.UnixEpoch;
... จากนั้นก็ใช้งานได้ดีแสดงค่าที่ถูกต้อง ทำให้ฉันสับสน
DebuggerDisplayAttribute
จะทำให้มันลองยากขึ้นเล็กน้อย