12

当前状态

有两个类:

[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; }
}

使用它们:

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

在调试器内部,显示的工具提示值a

一 = 5,二 = {DebuggerDisplayTest.B}

目标

我想要的是类似的东西

一 = 5,二 = '三 = 10'

我知道这可以通过覆盖ToString()class 的方法来实现B。这感觉不对,因为我在我的应用程序中编写代码仅用于调试。

我也知道使用类似于

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

也可以。这对我来说也感觉不对,因为它要求 classA具有 class 知识B

我希望有更多的方法将 type 的值“注入”DebuggerDisplayBclass 中该类型的实例A

问题

是否可以以某种方式访问​​“具有”复合类DebuggerDisplay的属性内的成员属性?DebuggerDisplay

更新

根据这个 SO answer,我的要求可能是不可能的。也许一个好的解决方案是ToString在类中重写B并做一些if..else并使用该Debugger.IsAttached属性仅在调试器内部表现不同。

就像是:

[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();
        }
    }
}
4

3 回答 3

5

从 OP 复制可能的解决方案

根据这个SO answer,我的要求可能是不可能的。也许一个好的解决方案是覆盖 B 类中的 ToString 并执行一些 if..else 并使用该Debugger.IsAttached属性仅在调试器内部表现不同。

就像是:

[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();
        }
    }
}
于 2014-02-08T12:01:37.283 回答
4

[免责声明我隶属于 OzCode]

您可以使用支持嵌套调试信息 的 OzCode 的显示功能。 好处是您不需要更改生产代码,一旦为实例定义了它,它将自动用于该类型的所有实例。揭示行动!

于 2015-10-08T11:48:51.280 回答
2

拼凑一些东西,我想出了这个解决方案。它有一个警告,它希望您遵循https://blogs.msdn.microsoft.com/jaredpar/2011/03/18/debuggerdisplay-attribute-best-practices/

[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()}";
}

你需要确保你有正确的导入,无论你在哪里粘贴这个帮助器与需要读取子调试器显示的代码相关。

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}]>";
    }
}

我觉得这是纯粹和实用主义之间相当公平的平衡,可以减少实现这一目标的摩擦。如果您不太关心纯度,您可以将 DebuggerDisplay 公开。我更喜欢 ReadDebuggerDisplay 以“无类型”方式运行(避免公开访问 DebuggerDisplay 所需的通用约束和接口)。

于 2016-03-21T18:08:11.537 回答