2011-08-23 5 views
5

まず、長いコード例は残念ですが、私は問題を説明する必要があると思います。一部のプロパティはウォッチリストの有効範囲外になるのはなぜですか?

デバッグのヘルプとして、私はしばしば私のオブジェクトに簡潔なオブジェクトサマリを返す "DebugString"メソッドを導入します。しかし、時には私のオブジェクトが複雑すぎて単一の文字列で最適に表現できないことがあるので、私は文字列リストを使用します。さて、Delphiの優れたデバッグビジュアライザを使ってオブジェクトを監視したいと思います。私がこれを行う方法は、文字列リストを再構築するゲッターでプロパティを導入することです。

このように動作しますが、トレースするすべての行についてプロパティが範囲外になるため、ウォッチウィンドウで虫めがねを再度クリックして値を確認する必要があります。どうしてこれなの?場所

  • ライン77(第2回「vMyObjにブレークポイントを "vMyObj.DebugStringList" と "vMyObj.DebugString" のための時計を追加

    program Project1; 
    
    {$APPTYPE CONSOLE} 
    
    uses 
        SysUtils, 
        Classes; 
    
    type 
        TMyClass = class 
        private 
        FInternalData : array[0..4] of integer; 
        FDebugStringList : TStringList; 
        procedure RebuildDebugStringlist; 
        function GetDebugStringList: TStringList; 
        function GetDebugString : string; 
        public 
        constructor Create; 
        destructor Destroy; override; 
        procedure Scramble; 
        property DebugStringList : TStringList read GetDebugStringList; 
        property DebugString : string read GetDebugString; 
        end; 
    
    constructor TMyClass.Create; 
    begin 
        FDebugStringList := TStringList.Create; 
    end; 
    
    destructor TMyClass.Destroy; 
    begin 
        FDebugStringList.Free; 
        inherited; 
    end; 
    
    function TMyClass.GetDebugString: string; 
    var 
        I : integer; 
    begin 
        Result := 'Object state: '; 
        for I := 0 to 3 do 
        Result := Result + inttostr(FInternalData[I])+' '; 
    end; 
    
    function TMyClass.GetDebugStringList: TStringList; 
    begin 
        RebuildDebugStringlist; 
        Result := FDebugStringlist; 
    end; 
    
    procedure TMyClass.RebuildDebugStringlist; 
    var 
        I : integer; 
    begin 
        FDebugStringList.Clear; 
    
        FDebugStringList.Add('Object state:'); 
        for I := 0 to 4 do 
        FDebugStringList.Add(inttostr(FInternalData[I])); 
    end; 
    
    procedure TMyClass.Scramble; 
    var 
        I : integer; 
    begin 
        for I := 0 to 4 do 
        FInternalData[I] := Random(100); 
    end; 
    
    var 
        vMyObj : TMyClass; 
    
    begin 
        vMyObj := TMyClass.Create; 
        try 
        vMyObj.Scramble; 
        vMyObj.Scramble; 
        vMyObj.Scramble; 
        finally 
        vMyObj.Free; 
        end; 
    
        readln; 
    end. 
    
    1. :、再現する新しいコンソールアプリケーションを作成するには

      「スクランブル」)、実行します。

    2. ビジュアライザ
    3. はビジュアライザがうまく動作することを確認して:)次の行を超える
    4. ステップを取得するには、次の「DebugStringList」時計に虫眼鏡をクリックします。ビジュアライザーは、時計が範囲外であることを示します。
    5. 虫眼鏡をもう一度押すと、オブジェクトの新しい状態が表示されます。

    なぜ時計が範囲外であると言っているのですか?これをどうすれば解決できますか?

    PS:私はデバッグビジュアライザを書くことができますが、いくつかの自動テストでは "DebugString"と "DebugStringList"を使用しています。この簡単な方法で実際に使用したいと思います。

    アップデート:私は、Delphi XE

    アップデート2使用:マルジャンVenema氏による良好な努力にもかかわらず を、私はまだこの問題に対する解決策を持っていません。私はEmbarcaderoにレポートを提出しました(QC番号98062、投票してください:-))。しかし、私はEmbarcaderoがこの問題を修正するのには時間がかかると思っています。私がまだ回避策に興味を持っているのを見て、私は小さな賞金を提供します。これまでに試したことはありませんでしたので、何が起こるか興味深いでしょう:-)

  • +1

    ここで使用しているデルファイのバージョンは何ですか? –

    +0

    私はXEを使っています(バージョン15.0.3890.34076が正確です) –

    答えて

    4

    Scrambleが実行されたときとまったく同じですので、範囲外です。バグは、ビジュアライザが範囲に戻ったときにリフレッシュされないことがあります。まだTStringsビジュアライザを見ていないのですが、回避策として、型なしのポインタ変数をFDebugStringListに使用して、そのTStringListの型キャストにそのderefencedポインタを置きます。

    var 
        vMyObj : TMyClass; 
        vSL: Pointer; 
    
    {$OPTIMIZATION OFF} 
    begin 
        vMyObj := TMyClass.Create; 
        try 
        vSL := @(vMyObj.FDebugStringList); 
    

    と時計には:

    TStringList(vSL^) 
    

    あなたは今、第二のスクランブルでブレークVSLのためのビジュアライザを開くと、FDebugStringListの内容が表示されます。その2番目のスクランブルを乗り越えると、「スクランブルが実行されている間に思考し、メインレベルに戻ったときに自分自身をリフレッシュする」ビジュアライザーを見ることができます。

    Pitfall:タイプされていないポインタ変数が最適化されていないことを確認する必要があります。したがって、デバッグ中に最適化がオフになっていることを確認してください。

    編集:残念ながら、残念ながら、回避策は時代遅れの値を示すようです。 Sveinのコメントを参照してください。

    更新

    免責事項:私はToolsAPIの専門家ではありません。 StringListVisualizerおよびToolsAPIユニットの大まかな検査では、RefreshVisualizerは「{ビジュアライザのデータを更新する必要があるときに呼び出されます}」と示されています。さらに、文字列 "RefreshVisualizer"は、ToolsAPIユニットのインタフェース宣言でのみ検出され、StringListVisualizerユニットで宣言され、実装されています。だから私の推測では、デバッガは、3回目のスクランブルコールで停止するように戻ったときに、デバッガがRefreshVisualizerを呼び出す必要があります。私の意見では、QCレポートに値する。少なくともそれは「ユーザーエクスペリエンスの欠点」です。

    +0

    あなたの答えをありがとう。残念ながら、この回避策は100%動作しません。ビジュアライザーに表示される値は古くなっています。 DebugStringListとDebugStringの両方を見ると、値が異なることがわかります。次のスクラブルをトレースすると、DebugStringの値がDebugStringListに表示され、* real *の値はDebugStringに表示されます。 –

    +0

    @Svein:ああ、それは気付かなかった。私はあなたがつづられていると思います。 EmbarcaderoでQCレポートを作成し、その番号をお知らせしたら、私は投票します。 –

    +0

    ありがとうございます。しかし、それはあなたが正しいと思われます。私は立ち往生している。私はEmbarcaderoに報告書を提出しました。 QC番号は98062です。 –

    1

    おそらく、ビジュアライザーは、スタックフレームがオフになっていても処理できませんし、短いゲッター関数はスタックフレームレスですか?

    最適化をオフにして、スタックフレームが役立つかどうかを確認し、その結果をQCに追加します。

    +0

    変更なし最適化はすでにオフになっていて、スタックフレームを無効にしても効果はありませんでした。 –

    +0

    のスタックフレームがオンになっている必要があります。しかし、大丈夫、それはテストされています:-) –

    1

    Are Delphi strings immutable?によれば、デルファイ文字列は書き込み時にコピーされるため、FDebugStringListをプロシージャ内で変更すると、古い文字列がスローされて範囲外になる可能性があります。

    同じコピーを再利用するために文字列を直接(ポインタ演算などを使用して)変更して、それが機能するかどうか確認できますか?もちろん、これはデバッグ出力の最大長を事前に知っていることを前提としており、それに応じて初期文字列長を設定することができます。

    +0

    これは動作するかどうかわかりませんが、それを行っても最適な解決策にはなりません。ビジュアライザーを使用して文字列ではなく_stringlist_を見たいと思います。 –

    関連する問題