2013-06-25 39 views
9

trạng thái hiện tạiCó thể truy cập thuộc tính con "DebuggerDisplay" của thuộc tính không?

Có hai lớp:

[DebuggerDisplay(@"One = {One}, two = {Two}")] 
public class A 
{ 
    public int One { get; set; } 
    public B Two { get; set; } 
} 

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 
} 

Sử dụng chúng:

var a = new A {One = 5, Two = new B {Three = 10}}; 

Bên trong debugger, giá trị đầu công cụ được hiển thị ở a

One = 5, two = {D ebuggerDisplayTest.B}

Goal

Những gì tôi muốn là một cái gì đó giống như

Một = 5, hai = 'Ba = 10'

Tôi biết điều này có thể đạt được bằng cách ghi đè phương thức ToString() của lớp B. Điều này chỉ cảm thấy không đúng, vì tôi đang viết mã trong ứng dụng của tôi để gỡ lỗi chỉ.

Tôi cũng biết rằng việc sử dụng một chuỗi tương tự như

[DebuggerDisplay(@"One = {One}, two = 'Three = {Two.Three}'")] 

sẽ làm việc, quá. Điều này cũng không cảm thấy phù hợp với tôi, vì nó đòi hỏi lớp học A có kiến ​​thức về lớp học B.

Tôi muốn có thêm một cách để "tiêm" giá trị DebuggerDisplay loại B vào thể hiện loại đó trong lớp A.

Câu hỏi

Có bằng cách nào đó có thể truy cập vào DebuggerDisplay thuộc tính của một thành viên bên trong DebuggerDisplay thuộc tính của một "có-một" lớp ghép?

Cập nhật

Có lẽ, yêu cầu của tôi là không thể thực hiện theo this SO answer. Có lẽ một giải pháp tốt sẽ là ghi đè ToString trong lớp B và thực hiện một số if..else và sử dụng Debugger.IsAttached property để hoạt động khác nhau chỉ bên trong trình gỡ lỗi.

Cái gì như:

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 

    public override string ToString() 
    { 
     if (Debugger.IsAttached) 
     { 
      return string.Format(@"Three = {0}", Three); 
     } 
     else 
     { 
      return base.ToString(); 
     } 
    } 
} 
+1

Liên quan: http://stackoverflow.com/questions/8677795/chaining-debuggerdisplay-on-complex-types –

Trả lời

3

sao chép giải pháp khả thi từ OP

Có lẽ, yêu cầu của tôi là không thể thực hiện theo SO answer này. Có lẽ một giải pháp tốt sẽ được ghi đè ToString trong lớp B và làm một số if..else và sử dụng Debugger.IsAttached property để hành xử khác nhau chỉ bên trong trình gỡ rối.

Cái gì như:

[DebuggerDisplay(@"Three = {Three}")] 
public class B 
{ 
    public int Three { get; set; } 

    public override string ToString() 
    { 
     if (Debugger.IsAttached) 
     { 
      return string.Format(@"Three = {0}", Three); 
     } 
     else 
     { 
      return base.ToString(); 
     } 
    } 
} 
3

[Disclaimer Tôi đang liên kết với OzCode]

Bạn có thể sử dụng OzCode của Reveal feature mà hỗ trợ thông tin debug lồng nhau. Reveal in action!
Mặt bổ sung là bạn không cần phải thay đổi mã sản xuất của mình và khi bạn xác định mã sản phẩm cho một phiên bản, nó sẽ được sử dụng tự động cho tất cả các trường hợp thuộc loại đó.

1

Ghép cùng một vài điều tôi đã đưa ra giải pháp này. Nó có báo trước nó hy vọng bạn làm theo https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/. Sử dụng C# 6 (compatible with Visual Studio 2013)

[DebuggerDisplay("{DebuggerDisplay,nq}")] 
public class B 
{ 
    public int Three { get; set; } 

    private string DebuggerDisplay => $"Three = {Three}"; 
} 

[DebuggerDisplay("{DebuggerDisplay,nq}")] 
public class A 
{ 
    public int One { get; set; } 
    public B Two { get; set; } 

    private string DebuggerDisplay => $"One = {One}, two = {Two.ReadDebuggerDisplay()}"; 
} 

Bạn sẽ cần phải chắc chắn rằng bạn có hàng nhập khẩu thích hợp cho nơi mà bạn từng dính helper này liên quan đến mã mà cần phải đọc màn hình gỡ rối trẻ em.

public static class ReflectionHelper 
{ 
    // https://stackoverflow.com/a/13650728/37055 
    public static object ReadProperty(
     this object target, 
     string propertyName) 
    { 
     var args = new[] {CSharpArgumentInfo.Create(0, null)}; 
     var binder = Binder.GetMember(0, propertyName, target.GetType(), args); 
     var site = CallSite<Func<CallSite, object, object>>.Create(binder); 
     return site.Target(site, target); 
    } 

    public static string ReadDebuggerDisplay(
     this object target, 
     string propertyName = "DebuggerDisplay") 
    { 
     string debuggerDisplay = null; 
     try 
     { 
      var value = ReadProperty(target, propertyName) ?? "<null object>"; 

      debuggerDisplay = value as string ?? value.ToString(); 
     } 
     catch (Exception) 
     { 
      // ignored 
     } 
     return debuggerDisplay ?? 
       $"<ReadDebuggerDisplay failed on {target.GetType()}[{propertyName}]>"; 
    } 
} 

Tôi cảm thấy đây là một sự cân bằng khá công bằng về tính thuần khiết và thực dụng để giảm ma sát khi đạt được điều này. Nếu bạn ít quan tâm về độ tinh khiết, bạn chỉ có thể làm cho DebuggerDisplay công khai. Tôi thích rằng ReadDebuggerDisplay hoạt động theo cách "loại-ít" (tránh các ràng buộc chung và các giao diện cần thiết để truy cập DebuggerDisplay công khai).

Các vấn đề liên quan