学习 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.


 
   

你可能感兴趣的:(list)