学习 TList 类的实现[8]

现在准备建立 Items 数组属性; 在 public 区输入下面代码:
property Items[Index: Integer]: Pointer;

执行 Shift+Ctrl+C 后的代码是:
...

  TMyList = class(TObject)
  private
    ...
    function GetItems(Index: Integer): Pointer;
    procedure SetItems(Index: Integer; const Value: Pointer);
  public
    ...
    property Items[Index: Integer]: Pointer read GetItems write SetItems;
  end;

implementation

{ TMyList }

...

function TMyList.GetItems(Index: Integer): Pointer;
begin

end;

procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin

end;

end.

 
 
 
 
 

 

 
  
在 TList 类中, GetItems 方法被命名为 Get; SetItems 方法被命名为 Put. 这里我们就不准备改名了.

分别实现如下:
function TMyList.GetItems(Index: Integer): Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.CreateFmt('异常:%d', [Index]);
  Result := FList^[Index];
end;

{同前, 在这里我们也没有触动 Notify 方法, 现在的 TMyList 也没有这个方法}
procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.CreateFmt('异常:%d', [Index]);

  if Value <> FList^[Index] then
    FList^[Index] := Value;
end;

 
 
 
 
 

 

 
  
至此, 我们可以使用 List.Itmes[i] 的方式访问列表中的元素了;

再进一步, 让它成为默认属性吧; 尽管只能选择一个属性为默认属性, 但哪一个属性能比它更重要的呢?
//只需把在 public 区声明的:
property Items[Index: Integer]: Pointer read GetItems write SetItems;

//改为:
property Items[Index: Integer]: Pointer read GetItems write SetItems; default;
Items 就是默认属性了, 这样再访问一个元素时, 即可以用: List.Itmes[i]; 也可以使用: List[i]. 默认属性真方便.

看看 TMyList 类目前的全部代码:
unit MyList;

interface

uses SysUtils;

const
  MaxListSize = Maxint div 16;

type
  PPointerList = ^TPointerList;
  TPointerList = array[0..MaxListSize - 1] of Pointer;

  TMyList = class(TObject)
  private
    FList: PPointerList;
    FCount: Integer;
    FCapacity: Integer;
    procedure SetCapacity(const Value: Integer);
    procedure SetCount(const Value: Integer);
    function GetItems(Index: Integer): Pointer;
    procedure SetItems(Index: Integer; const Value: Pointer);
  public
    destructor Destroy; override;
    function Add(Item: Pointer): Integer;
    procedure Clear;
    procedure Delete(Index: Integer);
    property Capacity: Integer read FCapacity write SetCapacity;
    property Count: Integer read FCount write SetCount;
    property List: PPointerList read FList;
    property Items[Index: Integer]: Pointer read GetItems write SetItems; default;
  end;

implementation

{ TMyList }

function TMyList.Add(Item: Pointer): Integer;
begin
  if FCount = FCapacity then SetCapacity(FCapacity + 4);
  FList^[FCount] := Item;
  Result := FCount;
  Inc(FCount);
end;

procedure TMyList.Clear;
begin
  SetCount(0);
  SetCapacity(0);
end;

procedure TMyList.Delete(Index: Integer);
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.CreateFmt('非法的 Index:%d', [Index]);
  if Index < FCount then
    System.Move(FList^[Index+1], FList^[Index], (FCount-Index)* SizeOf(Pointer));
  Dec(FCount);
end;

destructor TMyList.Destroy;
begin
  Clear;
  inherited;
end;

procedure TMyList.SetCapacity(const Value: Integer);
begin
  if (Value < FCount) or (Value > MaxListSize) then
    raise Exception.CreateFmt('非法数据:%d', [Value]);
  if FCapacity <> Value then
  begin
    ReallocMem(FList, Value * SizeOf(Pointer));
    FCapacity := Value;
  end;
end;

procedure TMyList.SetCount(const Value: Integer);
var
  i: Integer;
begin
  if (Value < 0) or (Value > MaxListSize) then
    raise Exception.CreateFmt('非法数据:%d', [Value]);
  if Value > FCapacity then SetCapacity(Value);
  if Value > FCount then
    FillChar(FList^[FCount], (Value - FCount) * SizeOf(Pointer), 0)
  else
    for i := FCount - 1 downto Value do
      Delete(I);
  FCount := Value;
end;

function TMyList.GetItems(Index: Integer): Pointer;
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.CreateFmt('异常:%d', [Index]);
  Result := FList^[Index];
end;

procedure TMyList.SetItems(Index: Integer; const Value: Pointer);
begin
  if (Index < 0) or (Index >= FCount) then
    raise Exception.CreateFmt('异常:%d', [Index]);

  if Value <> FList^[Index] then
    FList^[Index] := Value;
end;

end.

 
 
 
 
 

 

 
  
现在访问元素方便了, 重做上一个测试:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  end;

var
  Form1: TForm1;
implementation

{$R *.dfm}

uses MyList;

type
  TMyRec = record
    name: string[8];
    age : Word;
  end;

procedure TForm1.FormCreate(Sender: TObject);
var
  ListA: TMyList;
  r,r1,r2,r3,r4,r5: TMyRec;
begin
  ListA := TMyList.Create;

  r1.name := '张三';
  r1.age  := 11;
  ListA.Add(@r1);

  r2.name := '李四';
  r2.age  := 22;
  ListA.Add(@r2);

  r3.name := '王五';
  r3.age  := 33;
  ListA.Add(@r3);

  r4.name := '孙六';
  r4.age  := 44;
  ListA.Add(@r4);

  r5.name := '候七';
  r5.age  := 55;
  ListA.Add(@r5);


  {获取第三个元素}
  //r := TMyRec(ListA.List^[2]^);          {这是以前的代码}
  r := TMyRec(ListA[2]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {王五:33}

  {删除第三个元素后再访问第三个元素}
  ListA.Delete(2);
  //r := TMyRec(ListA.List^[2]^);          {这是以前的代码}
  r := TMyRec(ListA[2]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {孙六:44}

  {现在通过 Items 属性, 不仅可以取值, 还可以赋值}
  ListA[2] := @r1;
  r := TMyRec(ListA[2]^);
  ShowMessageFmt('%s:%d',[r.name, r.age]); {张三:11}

  ListA.Free;
end;

end.

 
 
 
 
 

 

 
  

你可能感兴趣的:(学习 TList 类的实现[8])