12

現在の状態

2 つのクラスを持つ:

[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

1 = 5、2 = {DebuggerDisplayTest.B}

ゴール

私が欲しいのは次のようなものです

1 = 5、2 = '3 = 10'

ToString()これは、 classのメソッドをオーバーライドすることで実現できることを知っていますB。私は自分のアプリケーションでデバッグ専用のコードを書いているので、これは正しくないと感じています。

また、次のような文字列を使用することも知っています

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

もうまくいくでしょう。Aclassには class の知識が必要になるため、これも私には適切ではありませんB

DebuggerDisplaytypeの値をBclass のその型のインスタンスに「注入」する方法がもっと欲しいAです。

質問

「has-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

4

[免責事項 私は OzCode と提携しています]

ネストされたデバッグ情報をサポート する OzCode のReveal 機能を使用できます。 プラス面は、本番コードを変更する必要がないことです。インスタンスに対してコードを定義すると、そのタイプのすべてのインスタンスに対して自動的に使用されます。アクションで公開!

于 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 に答える