Visual StudioデバッガーがToStringオーバーライドの評価を停止する理由は何ですか?

221
Jon Skeet 2015-07-23 02:12.

環境:Visual Studio 2015RTM。(私は古いバージョンを試していません。)

最近、Noda Timeコードの一部をデバッグしていて、タイプのローカル変数NodaTime.InstantstructNoda Timeの中心的なタイプの1つ)を取得すると、「ローカル」ウィンドウと「ウォッチ」ウィンドウがあることに気付きました。その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()、野田時間ではかなりの量の作業が行われていますが、確かに1秒もかかりません。したがって、デバッガーがToString()呼び出しの評価をあきらめる原因となる条件がさらにあると考えられます。そしてもちろん、それはとにかく構造体です。

スタック制限かどうかを確認するために繰り返し試行しましたが、そうではないようです。

では、VSが完全に評価するのを妨げている原因をどのように理解できInstant.ToString()ますか?以下に示すように、DebuggerDisplayAttribute役立つように見えますが、理由がわからない場合は、必要なときと不要なときに完全に自信を持つことはできません。

更新

を使用するとDebuggerDisplayAttribute、状況が変わります。

// For the sample code in the question...
[DebuggerDisplay("{ToString()}")]
public class DemoClass

私に与える:

demoClass      Evaluation timed out

一方、野田時間に適用すると:

[DebuggerDisplay("{ToString()}")]
public struct Instant

簡単なテストアプリで正しい結果が表示されます。

instant    "1970-01-01T00:00:00Z"

だから、おそらく野田時間の問題点は、いくつかの条件でDebuggerDisplayAttribute 行いを通じて力が-それはタイムアウトによる強制するものではありませんが。(これはInstant.ToString、タイムアウトを回避するのに十分な速さであるという私の期待に沿ったものです。)

これ十分な解決策かもしれませんが、何が起こっているのか、そしてNodaTimeのさまざまな値型すべてに属性を設定する必要をなくすためにコードを変更できるかどうかを知りたいのです。

好奇心旺盛で好奇心旺盛

デバッガーを混乱させるものは何でも、時々混乱させるだけです。を保持し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、構造体に変更すると、次のようになります。

instant    {NodaTime.Instant}
wrapper    {InstantWrapper}

したがって、クラス内にある別のメソッドによって呼び出される限り、評価できます。クラス/構造体の部分は、結果を得るために実行する必要のあるコードではなく、表示されている変数のタイプに基づいて重要であるように思われます。Instant.ToString()ToString

この別の例として、次を使用する場合:

object boxed = NodaConstants.UnixEpoch;

...その後、正常に動作し、適切な値が表示されます。私を混乱させてください。

1 answers

194
Patrick Nelson - MSFT 2015-07-23 07:05.

更新:

このバグはVisualStudio 2015 Update 2で修正されています。Update2以降を使用して構造体値でToStringを評価する際に問題が発生する場合は、お知らせください。

元の回答:

Visual Studio 2015で既知のバグ/設計の制限に遭遇し、構造体タイプでToStringを呼び出しています。これは、を扱うときにも観察できSystem.DateTimeSpanます。 System.DateTimeSpan.ToString()Visual Studio 2013の評価ウィンドウで機能しますが、2015年には常に機能するとは限りません。

低レベルの詳細に興味がある場合は、次のようになっています。

評価するためToStringに、デバッガーは「関数評価」と呼ばれるものを実行します。非常に簡単に言えば、デバッガーは現在のスレッドを除くプロセス内のすべてのスレッドを一時停止し、現在のスレッドのコンテキストをToString関数に変更し、非表示のガードブレークポイントを設定してから、プロセスを続行できるようにします。ガードブレークポイントに到達すると、デバッガーはプロセスを以前の状態に復元し、関数の戻り値を使用してウィンドウにデータを入力します。

ラムダ式をサポートするには、Visual Studio 2015でCLR式エバリュエーターを完全に書き直す必要がありました。大まかに言うと、実装は次のとおりです。

  1. Roslynは、式/ローカル変数のMSILコードを生成して、さまざまな検査ウィンドウに表示される値を取得します。
  2. デバッガーはILを解釈して結果を取得します。
  3. 「呼び出し」命令がある場合、デバッガーは上記のように関数評価を実行します。
  4. デバッガー/ roslynはこの結果を取得し、ユーザーに表示されるツリーのようなビューにフォーマットします。

ILが実行されるため、デバッガーは常に「実際の」値と「偽の」値の複雑な組み合わせを処理します。実際の値は、デバッグ中のプロセスに実際に存在します。偽の値は、デバッガプロセスにのみ存在します。適切な構造体セマンティクスを実装するために、デバッガーは構造体値をILスタックにプッシュするときに常に値のコピーを作成する必要があります。コピーされた値は「実際の」値ではなくなり、デバッガープロセスにのみ存在するようになりました。つまり、後での関数評価を実行する必要がある場合ToString、プロセスに値が存在しないため、実行できません。値を取得しようとするには、ToStringメソッドの実行をエミュレートする必要があります。いくつかのことをエミュレートすることはできますが、多くの制限があります。たとえば、ネイティブコードをエミュレートしたり、「実際の」デリゲート値の呼び出しやリフレクション値の呼び出しを実行したりすることはできません。

これらすべてを念頭に置いて、表示されているさまざまな動作の原因は次のとおりです。

  1. デバッガーが評価していませんNodaTime.Instant.ToString->これは、構造体タイプであり、ToStringの実装を上記のようにデバッガーでエミュレートできないためです。
  2. Thread.SleepToString構造体で呼び出されたときに時間がかからないようです->これはエミュレータが実行されているためToStringです。Thread.Sleepはネイティブメソッドですが、エミュレーターはそれを認識しており、呼び出しを無視します。これは、ユーザーに表示する値を取得するために行います。この場合、遅延は役に立ちません。
  3. DisplayAttibute("ToString()")動作します。->それは紛らわしいです。暗黙の呼び出しの唯一の違いToStringDebuggerDisplay暗黙的のいずれかのタイムアウトということでToString 評価はすべて、暗黙的な無効になりToString、次のデバッグセッションまで、そのタイプのための評価を。あなたはその行動を観察しているかもしれません。

設計上の問題/バグに関しては、これはVisualStudioの将来のリリースで対処することを計画しているものです。

うまくいけば、それは物事をクリアします。他にご不明な点がありましたらお知らせください。:-)

Related questions

MORE COOL STUFF

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは3日間一緒に夫と一緒に寝て、25年経ってもまだ夫と結婚しています

ケイト・ブランシェットは、夫に会ったとき、典型的な交際のアドバイスに逆らいました。

マイケルシーンが非営利の俳優である理由

マイケルシーンが非営利の俳優である理由

マイケルシーンは非営利の俳優ですが、それは正確にはどういう意味ですか?

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

ホールマークスターのコリンエッグレスフィールドがRomaDramaLiveでスリル満点のファンと出会う![エクスクルーシブ]

特徴的なスターのコリン・エッグレスフィールドは、RomaDrama Liveでのスリル満点のファンとの出会いについて料理しました!加えて、大会での彼のINSPIREプログラム。

「たどりつけば」をオンラインでストリーミングできない理由

「たどりつけば」をオンラインでストリーミングできない理由

ノーザンエクスポージャーが90年代の最も人気のある番組の1つになった理由を確認するには、Blu-rayまたはDVDプレーヤーをほこりで払う必要があります。

バイオニック読書はあなたをより速く読むことができますか?

バイオニック読書はあなたをより速く読むことができますか?

BionicReadingアプリの人気が爆発的に高まっています。しかし、それは本当にあなたを速読術にすることができますか?

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖:アクセスは簡単ではありませんが、ハイキングする価値があります

ドミニカのボイリング湖は、世界で2番目に大きいボイリング湖です。そこにたどり着くまでのトレッキングは大変で長いですが、努力する価値は十分にあります。

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

私たちの水をきれいに保つのを助けるためにあなたの髪を寄付してください

サロンからのヘアトリミングや個人的な寄付は、油流出を吸収して環境を保護するのに役立つマットとして再利用できます。

ホワイトハウスの最も記憶に残る結婚式を見てください

ホワイトハウスの最も記憶に残る結婚式を見てください

過去200年以上の間にホワイトハウスで結婚したのはほんの数人です。彼らは誰でしたか、そしてそこで結婚式を獲得するために何が必要ですか?

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ねえNFL、ジョーバロウとカイラーマレーは女性の権利をサポートするために少しの助けを使うことができます

ジョー・バロウロー対ウェイド事件の転覆に対応するNFLは、言葉を言わないことで、腹立たしいが予測可能なPRの結果でした。

別の日、別のヒンジのないLIV記者会見

別の日、別のヒンジのないLIV記者会見

(lから)パット・ペレス、ブルックス・ケプカ、パトリック・リードサウジアラビアのLIVゴルフリーグのさらに別の信じられないほどの記者会見で、スポーツのファンはブルックス・ケプカからでたらめな吐き気と質問回避の驚異的なマスタークラスを受けました。パトリックリード、ブライソンデシャンボー、パットペレス、最近のPGAツアーの脱北者。

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

ミズ・マーベルの家族の帰郷は悪役よりも激しく打撃を与える

レッドダガーとマーベルさんがチームを組んでいます。

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

6億7500万ドルのビットコインローンのデフォルト後にすべての資産を清算するように命じられたスリーアローズキャピタル

暗号業界最大の沈没船の1つであるスリーアローズキャピタルは、ついにその悲惨さから解放されています。火曜日に、不良債権ヘッジファンドは、債権者からの返済を要求する訴訟の高まりに応えて、バージンアイランド裁判所によって清算を命じられました彼らが3ACに行ったローン。

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya Wishes Boyfriend Tom Holland Happy Birthday with Cuddly Photo: He 'Makes Me the Happiest'

Zendaya shared a sweet photo in honor of boyfriend Tom Holland's 26th birthday Wednesday

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

小さな女性:脳卒中を患った後に病院から解放されたアトランタのジューシーな赤ちゃん:「まだ癒し」

シーレン「Ms.JuicyBaby」ピアソンは、先月脳卒中で入院した後、「もう一度たくさんのことをする方法を学ばなければならない」ため、言語療法を受けていることを明らかにしました。

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

エマストーンは彼女のクリフサイドマリブビーチハウスを420万ドルでリストアップしています—中を見てください!

オスカー受賞者の世紀半ばの家には、3つのベッドルーム、2つのバス、オーシャンフロントの景色があります。

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、母乳育児の経験の中で、彼女は「本当に、本当に落ち込んでいる」と言います

ジーニー・メイ・ジェンキンスは、生後4か月の娘、モナコに母乳育児をしていると語った。

Suffragettes Indicam #3: Junho

Suffragettes Indicam #3: Junho

Mais um mês se findando — e metade do ano de 2022 já passou. Sabe o que isso significa? Não, não é hora de verificar se você está cumprindo com suas resoluções de Ano Novo.

Calin (Estudo de Caso UX/UI Design)

Calin (Estudo de Caso UX/UI Design)

Este projeto foi desenvolvido a partir de briefing fictício disponibilizado pelo site Tifólio, uma plataforma para designers. Briefing Matriz CSD Como ponto inicial utilizei como base algumas notícias atuais sobre meios de pagamento digital e com essas informações desenvolvi a Matriz CSD.

多元宇宙—Junø

多元宇宙—Junø

チェーン間アカウントがJunoに登場します。異なるブロックチェーン間でスマートコントラクトの構成可能性と真の相互運用性を提供します。

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

#brand【ベター・コール・ソール!アメリカのテレビシリーズ「ブレイキング・バッド」に最高のビジネス例が隠されている】・・・ルールクリエイティブ

1.ドラマを見た後、起業する考えはありますか?あなたのビジネスはボトルネックに遭遇しましたか?方向性がなくてわからない場合は、ドラマを追いかけて行くことを心からお勧めします。(?)ブラフではなく、最も完璧なビジネス例を隠すドラマがあります。2.ブレイキング・バッドとその弁護士ドラマ「ブレイキング・バッド」を見た友人たちは、演劇の中で、穏やかな表情で、弁護士のソウル・グッドマンに深く感銘を受けなければなりません。口を開けて、感覚の弱い傭兵の性格を持っています。道徳の面で、サル・グッドマンは無意識のうちに劇に欠かせない役割を果たし、彼自身のシリーズ「絶望的な弁護士」(ベター・コール・ソール)を生み出しました。ウェントウのテキストとビデオは、劇中のソウル・グッドマンのテレビコマーシャルです。製品(サービス)、競争戦略、市場ポジショニング、ブランド名、ターゲット顧客グループ、コミュニケーション軸から広告まで、サル・グッドマンの役割のビジネス設定は、「最低」と見なすことができる超超超超超超完全です。ブランドコミュニケーションのコスト」「変化」のモデル。なぜ?私の分析をご覧ください。3.ソウル・グッドマンの「事業戦略」1.基本情報ブランド名:Saul Goodman製品:法律相談サービス対象顧客:麻薬中毒、飲酒運転、事故など。法律知識の欠如は、一般的に公立弁護士にしか余裕がなく、真面目な弁護士も「特別な法律を持つ消費者」を避けます。恐れてはいけない「​​ニーズ」。コミュニケーションの主軸:この国のすべての男性、女性、子供は有罪判決を受けるまで無実だと思います。地域:アルバカーキ市スローガン:Thrallに電話したほうがいいです!(ベター・コール・ソール)広告:2つの可能性のある犯罪状況をシミュレートします+サウルの主張+サウルのスローガン2をより適切に呼び出します。

Language