[解決済み】Visual StudioデバッガがToStringオーバーライドの評価を停止する理由は何ですか?
質問
環境は?Visual Studio 2015 RTMです。(古いバージョンは試していません)
最近、いくつかのデバッグで
野田時間
のコードで、ローカル変数に
NodaTime.Instant
(中央の
struct
のタイプは、quot;Locals" と "Watch" のウィンドウは、その
ToString()
をオーバーライドします。もし私が
ToString()
をウォッチウィンドウで明示的に表示すると、適切な表現が表示されますが、そうでない場合は、ただ表示されるだけです。
variableName {NodaTime.Instant}
というのはあまり意味がない。
オーバーライドで定数文字列を返すように変更すると、文字列が は デバッガに表示されるので、それがそこにあることは明らかにわかりますが、quot;normal" の状態では使いたくないだけです。
これをローカルに小さなデモアプリで再現してみたところ、以下のようになりました。(この投稿の初期バージョンでは
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()
を評価するのをあきらめるような条件は、もっとたくさんあると思われます。
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
は、タイムアウトを回避するのに十分な速度が簡単に得られます)。
これは かもしれない しかし、何が起こっているのか、そして、Noda Timeの様々な値タイプすべてに属性を付ける必要がないように、単純にコードを変更することができるのか、知りたいのです。
ますます気になる
デバッガーを混乱させるものは何でも、時々混乱させるだけです。では、次のようなクラスを作ってみよう。
ホールド
an
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;
...すると、正しい値が表示され、正常に動作します。私は混乱しています。
解決方法は?
アップデートしてください。
この不具合は、Visual Studio 2015 Update 2で修正されました。 Update 2以降を使用しても、構造体値のToStringの評価に問題がある場合は、お知らせください。
オリジナルの回答です。
Visual Studio 2015で、構造体型のToStringを呼び出すと、既知のバグ/設計上の制限に遭遇しています。 また、この現象は
System.DateTimeSpan
.
System.DateTimeSpan.ToString()
は、Visual Studio 2013では評価ウィンドウで動作しますが、2015では必ずしも動作しません。
低レベルな内容に興味がある方は、こちらをご覧ください。
を評価するために
ToString
デバッガーは、いわゆる「関数評価」を行います。 非常に単純化すると、デバッガーは現在のスレッドを除くプロセス内のすべてのスレッドを一時停止し、現在のスレッドのコンテキストを
ToString
関数を実行し、隠れたガードブレークポイントを設定し、プロセスの継続を許可します。 ガードブレークポイントに達すると、デバッガはプロセスを以前の状態に戻し、関数の戻り値を使用してウィンドウにデータを入力します。
ラムダ式に対応するために、Visual Studio 2015のCLR Expression Evaluatorを完全に書き換える必要がありました。 高水準で、実装は
- Roslynは式/ローカル変数のMSILコードを生成し、各種検査ウィンドウに表示する値を取得します。
- デバッガはILを解釈して結果を得る。
- call"命令がある場合、デバッガは以下の処理を実行します。 のように関数を評価します。
- デバッガ/ロスリンは、この結果を受け取り、それをフォーマットして ツリー状に表示し、ユーザーに見せる。
デバッガーはILを実行するため、常に本物と偽物が混在した複雑な値を扱っています。 リアルな値は、デバッグ対象のプロセス内に実際に存在します。 偽の値はデバッガー プロセスにのみ存在します。 適切な構造体セマンティクスを実装するために、デバッガーは構造体の値を IL スタックにプッシュするときに、常に値のコピーを作成する必要があります。 コピーされた値は、もはや本物の値ではなく、デバッガープロセス内にのみ存在します。 つまり、後で
ToString
というのは、その値がプロセス内に存在しないからです。 この値を取得するためには
ToString
メソッドを使用します。 エミュレートできることもありますが、多くの制限があります。 例えば、ネイティブコードをエミュレートすることはできませんし、"real" デリゲート値への呼び出しやReflection値への呼び出しを実行することはできないのです。
それらを踏まえて、あなたが見ているさまざまな動作の原因を考えてみましょう。
-
デバッガーは
NodaTime.Instant.ToString
-> これは 構造体型であり、ToString の実装は は、上記のようにデバッガによってエミュレートされます。 -
Thread.Sleep
によって呼び出された場合、時間はゼロになるようです。ToString
を搭載しています。 struct -> これは、エミュレータが実行するToString
. Thread.Sleepはネイティブメソッドですが、エミュレータはそれを認識しています。 を呼び出すと、それを無視します。 これは、値を取得しようとするために行うものです。 を表示させることができます。 この場合、遅延は役に立ちません。 -
DisplayAttibute("ToString()")
の作品です。->それは紛らわしいですね。 唯一 の暗黙の呼び出しの違いはToString
とDebuggerDisplay
のタイムアウトは、暗黙的なToString
を評価すると、すべての暗黙のToString
設計上の問題/バグに関しては、Visual Studioの将来のリリースで対応する予定です。
これですっきりしたかな。 また質問があれば教えてください :-)
関連
-
[解決済み】ソケットのアドレス(プロトコル/ネットワークアドレス/ポート)は、通常1つしか使用できない?
-
[解決済み] なぜList<T>を継承しないのですか?
-
[解決済み] Visual Studioでデバッグ中にリターンする前に戻り値を調べることはできますか?
-
[解決済み] Visual Studio 2015 の .vs フォルダをソースコントロールに追加した方が良いですか?
-
[解決済み】デバッガでステップインツーとステップオーバーの違いは何ですか?
-
[解決済み】Visual Studio C++で、メモリ割り当ての表現とは何ですか?
-
[解決済み】Visual Studioデバッガで値を変更するとブレークする件
-
[解決済み】デバッグ開始時にVisual Studioが新しいブラウザウィンドウを起動しないようにするには?
-
[解決済み] Visual Studioデバッガ - 整数値を16進数で表示する
-
[解決済み】Visual Studio 2015の「共有プロジェクト」と「クラスライブラリ」の違いとは?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] エンティティタイプ ApplicationUser は、現在のコンテキストのモデルの一部ではありません。
-
[解決済み】「namespace x already contains a definition for x」エラーの修正方法は?VS2010にコンバートした後に発生しました。
-
[解決済み】バックスラッシュを含むパス文字列のエスケープシーケンスが認識されない件
-
[解決済み】WPFでXamlファイルにコメントを追加する方法は?
-
[解決済み】Swashbuckle/Swagger + ASP.Net Core: "Failed to load API definition" (API定義の読み込みに失敗しました
-
[解決済み】Visual Studio: 操作を完了できませんでした。パラメータが正しくありません
-
[解決済み】IntPtrとは一体何なのか?
-
[解決済み] 関数を終了するには?
-
[解決済み】データが存在しないのに読み込もうとする試みが無効である
-
[解決済み】スレッド終了またはアプリケーションの要求により、I/O操作が中断されました。