• 分析 TStringList 存取对象的特点 还是回复 Test1234 的问题


    问题来源: http://www.cnblogs.com/del/archive/2008/04/26/973346.html#1171927

    在 Delphi 中存储系列对象, 大家常用 TList 类; 有了 TObjectList(在 Contnrs 单元)以后, 存储对象就有了更好的选择, 因为从 TObjectList 列表中移除的对象同时会得到释放.

    很少有人使用 TStringList 储存对象, 殊不知用 TStringList 储存对象也有 TList 和 TObjectList 所不及的优势.

    我想在继续探讨前先重复一个概念: 对象的 "指针" 和 "首地址":
    我们通过对象的指针可以找到对象, 也就是说指针是指向了对象; 对象也不过是一系列数据, "指针" 一般是指向这组数据的 "首地址".
    下面代码可以获取 Button1 对象的 "指针" 和 "首地址":
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ShowMessageFmt('指针: %d', [Integer(@Button1)]);  {14910416}
      ShowMessageFmt('首地址: %d', [Integer(Button1)]); {15011440}
    end;
    
    我们再看下 TList、TObjectList 和 TStringList 添加对象的方法声明:
    TList       : function Add(Item: Pointer): Integer;
    TObjectList : function Add(AObject: TObject): Integer;
    TStringList : function AddObject(const S: string; AObject: TObject): Integer;
    
    可以看出, TList 添加的只是指针; TObjectList 和 TStringList 添加的类型是对象.
    添加对象时, 是把整个对象的数据都添加进去吗? 当然不是, 只要记住对象的首地址就可以了(应该也是用类似指针的办法, 我没仔细研究), 测试代码:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
    begin
      ShowMessageFmt('指针: %d', [Integer(@Button1)]);  {14910416}
      ShowMessageFmt('首地址: %d', [Integer(Button1)]); {15011440}
    
      List := TStringList.Create;
      List.AddObject('btn', Button1);
      ShowMessageFmt('取出: %d', [Integer(List.Objects[0])]); {15011440, 可以看出相同与上面的首地址}
      List.Free;
    end;
    
    通过 TStringList 的 AddObject 和 InsertObject 方法可以添加对象;
    用 Objects[] 属性取出对象; 用 List[] 取出字符串. 示例:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
      obj: TObject;
      str: string;
    begin
      List := TStringList.Create;
      List.AddObject('btn', Button1);    {添加}
    
      obj := List.Objects[0];            {取出对象}
      str := List[0];                    {取出字串}
    
      {使用对象, 有个前提:我们知道它属于 TButton}
      ShowMessage(TButton(obj).Caption); {Button1}
      ShowMessage(str);                  {btn}
    
      List.Free;
    end;
    
    添加对象的指针可以吗? 可以, 但需要转换成无类型指针, 例:
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
      obj: TObject;
    begin
      List := TStringList.Create;
      List.AddObject('btn', Pointer(@Button1));
      List.AddObject('btn', Pointer(Button1)); {这样也可以}
      obj := List.Objects[0];
      ShowMessage(TButton(obj).Caption); {显示: Button1}
      List.Free;
    end;
    
    既然也可以添加指针, 那我们也可以添加不属于 TObject 的结构等其他指针;
    假如不能添加指针, 也将无法添加结构, 因为结构不属于 TObject. 举例:
    type
      PMyRec = ^TMyrec;
      TMyRec = record
        s: string;
        i: Integer;
      end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
      R1,R2: TMyRec;
    begin
      List := TStringList.Create;
    
      R1.s := 'abc';
      R1.i := 123;
      List.AddObject('rec', Pointer(@R1)); 
      //List.AddObject('rec', @R1); {结构比较特殊, 不转无类型指针也可以}
    
      R2 := PMyRec(List.Objects[0])^;
      ShowMessageFmt('%s,%d', [R2.s, R2.i]); {abc,123}
    
      List.Free;
    end;
    
    前面说到 TStringList 还会有点优势; 首先得承认它的劣势, 因为它是两组数据构成的列表, 在数据量特别大的时候效率上会有劣势; 现在说说它的优势:
    从 TList 和 TObjectList 取出的对象类型是未知的(当然作者知道), 所以一般只能存储单一类型的对象;
    因为 TStringList 有两个字段, 我们可以用那个 String 字段来储存对象类型, 从而让 TStringList 可以同时储存更多类型的对象. 举例:
    unit Unit1;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
      Dialogs, StdCtrls;
    
    type
      TForm1 = class(TForm)
        Button1: TButton;
        procedure Button1Click(Sender: TObject);
      end;
    
    var
      Form1: TForm1;
    
    implementation
    
    {$R *.dfm}
    type
      PMyRec = ^TMyrec;
      TMyRec = record
        s: string;
        i: Integer;
      end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      List: TStringList;
      R1,R2: TMyRec;
      str: string;
      i: Integer;
    begin
      List := TStringList.Create;
    
      R1.s := 'abc';
      R1.i := 123;
      str := '我是字符串';
      List.AddObject('1', @R1);           {用 1 表示结构 TMyRec}
      List.AddObject('2', Sender);        {用 2 表示 TButton}
      List.AddObject('3', Self);          {用 3 表示 TForm1}
      List.AddObject('4', Pointer(str));  {用 4 表示 String}
    
      for i := 0 to List.Count - 1 do
      begin
        case StrToIntDef(List[i], 0) of
          1: begin
               R2 := PMyRec(List.Objects[i])^;
               ShowMessageFmt('%s,%d', [R2.s, R2.i]);       {abc,123}
             end;
          2: ShowMessage(TButton(List.Objects[i]).Caption); {Button1}
          3: ShowMessage(TForm1(List.Objects[i]).Text);     {Form1}
          4: ShowMessage(PChar(List.Objects[i]));           {我是字符串}
        end;
      end;
    
      List.Free;
    end;
    
    end.
    
  • 相关阅读:
    详解JavaScript中的this
    java静态代理与动态代理简单分析
    BZOJ1263 [SCOI2006]整数划分
    BZOJ1258 [CQOI2007]三角形
    BZOJ1237 [SCOI2008]配对
    BZOJ1257 [CQOI2007]余数之和
    BZOJ1103 [POI2007]大都市
    BZOJ1061 [NOI2008]志愿者招募
    BZOJ1050 [HAOI2006]旅行
    BZOJ1055 [HAOI2008]玩具取名
  • 原文地址:https://www.cnblogs.com/del/p/1172589.html
Copyright © 2020-2023  润新知