现在准备建立 Items 数组属性; 在 public 区输入下面代码:
property Items[Index: Integer]: Pointer;
执行 Shift+Ctrl+C 后的代码是:
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.