2011-08-23 24 views
5

Trước hết, xin lỗi cho ví dụ mã dài dòng, nhưng tôi tin rằng nó là cần thiết để minh họa cho vấn đề của tôi.Tại sao một số thuộc tính nằm ngoài phạm vi trong danh sách theo dõi, trong khi một số thuộc tính khác thì không?

Là trợ giúp gỡ lỗi, tôi thường giới thiệu phương pháp "DebugString" trên đối tượng của tôi, trả về một tóm tắt đối tượng súc tích. Nhưng đôi khi các đối tượng của tôi quá phức tạp để được biểu diễn tối ưu trong một chuỗi, vì vậy tôi sử dụng các chuỗi danh sách. Bây giờ, tôi muốn sử dụng các visualizers debug tuyệt vời trong Delphi để theo dõi đối tượng của tôi. Cách tôi làm điều này là để giới thiệu một tài sản với một getter mà xây dựng lại danh sách chuỗi.

Loại này hoạt động, nhưng đối với mỗi dòng tôi theo dõi, thuộc tính vượt quá phạm vi, vì vậy tôi phải nhấp lại vào kính lúp trong cửa sổ xem để xem giá trị. Tại sao điều này?

Để tái sản xuất, tạo ra một giao diện điều khiển ứng dụng mới:

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. Thêm đồng hồ cho "vMyObj.DebugStringList" và "vMyObj.DebugString"
  2. Đặt một breakpoint trên dòng 77 (thứ 2 "vMyObj .Scramble ") và chạy.
  3. Nhấn vào biểu tượng kính lúp bên cạnh "DebugStringList" đồng hồ để có được những visualizer
  4. Quan sát rằng visualizer hoạt động độc đáo :)
  5. Bước trên dòng tiếp theo. Trình hiển thị trực quan hiện cho biết đồng hồ nằm ngoài phạm vi.
  6. Nhấn lại kính lúp để xem trạng thái mới của đối tượng.

Tại sao trình hiển thị cho biết đồng hồ nằm ngoài phạm vi? Làm thế nào tôi có thể sửa lỗi này?

PS: Tôi biết tôi có thể viết trình hiển thị gỡ lỗi, nhưng tôi sử dụng "DebugString" và "DebugStringList" trong một số thử nghiệm tự động và tôi thực sự muốn sử dụng chúng theo cách dễ dàng này.

Cập nhật: Tôi sử dụng Delphi XE

Cập nhật 2: Mặc dù một nỗ lực tốt bằng cách Marjan Venema, tôi vẫn không có giải pháp cho vấn đề này. Tôi đã gửi báo cáo với Embarcadero (số QC 98062, vui lòng bỏ phiếu :-)). Tuy nhiên, tôi nghi ngờ nó sẽ mất một thời gian cho Embarcadero khắc phục vấn đề này, và nhìn thấy làm thế nào tôi vẫn còn quan tâm đến một workaround, tôi sẽ cung cấp một tiền thưởng nhỏ. Không bao giờ thử điều đó trước đây, vì vậy sẽ rất thú vị nếu bạn muốn điều gì xảy ra :-)

+1

Bạn đang sử dụng phiên bản Delphi nào ở đây? –

+0

Tôi đang trên XE (phiên bản 15.0.3890.34076 chính xác) –

Trả lời

4

Nó nằm ngoài phạm vi vì đó chính là điều xảy ra khi Scramble được thực hiện. Các lỗi có thể trong đó visualizer không nhận được làm mới khi nó trở lại vào phạm vi. Đã không có một cái nhìn tại visualizer TStrings được nêu ra, nhưng một công việc xung quanh là sử dụng một biến con trỏ untyped để FDebugStringList và đặt một chiếc đồng hồ trên một typecast của TStringList đó con trỏ derefenced.

var 
    vMyObj : TMyClass; 
    vSL: Pointer; 

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

và chiếc đồng hồ trên:

TStringList(vSL^) 

Khi bây giờ bạn phá vỡ vào tranh giành thứ hai, mở visualizer cho VSL, bạn sẽ thấy nội dung của FDebugStringList. Khi bạn bước qua cuộc tranh giành thứ hai, bạn có thể thấy visualizer "suy nghĩ trong khi tranh giành thực hiện và sau đó làm mới chính nó khi bạn trở lại mức chính".

Pitfall: bạn cần đảm bảo biến con trỏ không được lấy mẫu không được tối ưu hóa. Vì vậy, hoặc là làm cho một số sử dụng không tầm thường của nó chắc chắn rằng tối ưu hóa là tắt trong khi gỡ lỗi.

Chỉnh sửa: Rất tiếc, có vẻ như công việc xung quanh hiển thị các giá trị lỗi thời. Xem bình luận của Svein.

Cập nhật

Disclaimer: Tôi không có chuyên môn ToolsAPI. Một kiểm tra cursory của StringListVisualizer và các đơn vị ToolsAPI cho thấy rằng RefreshVisualizer là "{Được gọi khi dữ liệu cho visualizer cần phải được làm mới}". Hơn nữa, chuỗi "RefreshVisualizer" chỉ được tìm thấy trong khai báo giao diện trong đơn vị ToolsAPI và được khai báo và được triển khai trong đơn vị StringListVisualizer. Vì vậy, tôi đoán tại thời điểm này là trình gỡ lỗi nên gọi RefreshVisualizer khi trở lại để dừng lại trên cuộc gọi Scramble thứ ba, nhưng không. Đánh giá một báo cáo QC theo ý kiến ​​của tôi. Ít nhất nó là một "thiếu kinh nghiệm người dùng".

+0

Cảm ơn câu trả lời của bạn. Thật không may, workaround không hoạt động 100%. Các giá trị hiển thị trong trình hiển thị hình ảnh đã lỗi thời. Nếu bạn xem cả DebugStringList và DebugString, bạn sẽ thấy rằng các giá trị là khác nhau và khi bạn theo dõi trên gải tiếp theo, các giá trị từ DebugString hiển thị trong DebugStringList, trong khi các giá trị * real * được hiển thị trong DebugString. –

+0

@Svein: Oh bugger, không nhận thấy điều đó. Tôi đoán bạn bị mắc kẹt rồi. Nếu bạn gửi một báo cáo QC với Embarcadero và cho tôi biết số của nó, tôi sẽ bỏ phiếu cho nó. –

+0

Cảm ơn bạn đã thử. Nhưng có vẻ như bạn là chính xác; Tôi bị kẹt. Tôi đã gửi một báo cáo với Embarcadero. Số QC là 98062. –

1

Có thể trình hiển thị hình ảnh không hoạt động tốt với các khung xếp chồng bị tắt và các hàm getter ngắn không có chồng xếp chồng?

Xem liệu tắt tối ưu hóa và khung xếp chồng có hiệu quả không và thêm kết quả vào QC của bạn.

+0

Không thay đổi. Tối ưu hóa đã tắt và việc tắt các khung xếp chồng không có tác dụng. –

+0

các khung xếp chồng nên được bật. Nhưng ok, nó được kiểm tra :-) –

1

Theo Are Delphi strings immutable?, chuỗi Delphi được sao chép khi ghi - vì vậy khi bạn thay đổi FDebugStringList bên trong quy trình RebuildDebugStringlist, có thể là vứt bỏ chuỗi cũ, khiến cho nó nằm ngoài phạm vi.

Bạn có thể cố gắng sửa đổi chuỗi trực tiếp (sử dụng số học con trỏ, v.v.) để sử dụng lại cùng một bản sao và xem nó có hoạt động không? Tất nhiên điều này giả định bạn biết chiều dài tối đa của đầu ra gỡ lỗi trước và có thể thiết lập độ dài chuỗi ban đầu cho phù hợp.

+0

Tôi không biết liệu điều này có hiệu quả hay không, nhưng ngay cả khi nó đã làm nó nó sẽ không phải là giải pháp tối ưu. Tôi muốn sử dụng trình hiển thị để xem _stringlist_ chứ không phải chuỗi. –

Các vấn đề liên quan