☆TListを使ったリスト No1
その昔、ポインタを繋いだり、繋ぎ変えたり、ガベージコレクションさせたりと誰もが自作リストでクラス(当時はレコード型だったかな)を管理していました。しかしDelphiには、TListという汎用性のあるリストが用意されていますので、わざわざ可読性の悪いリストを自作する必要はないです。
さて、そのTListですがポインタを扱うので、次のように型キャストが必要になります。
これだとやはり可読性がよくない!ということで、特定のクラスを管理するリストを作ってみたいと思います。 人によっては、MyList = class(TList)という形で作られておられますが、 この場合、TListのメンバーに直接アクセスできる、すなわちポインタとしても扱えるためどんな型も 管理することができてしまいます。となるとバグが潜む可能性が出てきますよね。
(この方法を否定しているわけではないです)
ということで、私はTListをprivateなフィールドにしたクラスが好きです(笑)
せっかくなので拡張性を持たせたサンプルを作っていきたいと思います。
リストの読み書きを汎用ポインタではなく、THRBaseクラスで行えるようにしています。
なぜTObjectではなくて、TPersistentから継承しているのか、疑問に思われる方も多いかも知れませんね。 その理由は、私が作るリストの中では、TPersistentのAssignという仮想メソッドを再定義することが多いからです(笑)
※procedure Assign(Source: TPersistent); override; という部分ですね。
今回は、単純なクラスを拡張していくという目的で作っているので、少し回りくどい処理になっているかも知れません。 HRBaseClassesを取り込んだ形でいきなり「TListを使ったリスト No2」のMySampleClassesにあるクラスを作ることも多いです。
☆TListを使ったリスト No1
☆TListを使ったリスト No2
☆TListを使ったリスト No3
さて、そのTListですがポインタを扱うので、次のように型キャストが必要になります。
procedure TForm1.Button1Click(Sender: TObject); var List: TList; I: Integer; begin List := TList.Create; try List.Add(TStringList.Create); TStringList(List[0]).Text := 'delphi-fan'; Memo1.Lines.Assign(TStringList(List[0])); finally for I := 0 to List.Count - 1 do TStringList(List[I]).Free; List.Free; end; end;
これだとやはり可読性がよくない!ということで、特定のクラスを管理するリストを作ってみたいと思います。 人によっては、MyList = class(TList)という形で作られておられますが、 この場合、TListのメンバーに直接アクセスできる、すなわちポインタとしても扱えるためどんな型も 管理することができてしまいます。となるとバグが潜む可能性が出てきますよね。
(この方法を否定しているわけではないです)
ということで、私はTListをprivateなフィールドにしたクラスが好きです(笑)
せっかくなので拡張性を持たせたサンプルを作っていきたいと思います。
リストの読み書きを汎用ポインタではなく、THRBaseクラスで行えるようにしています。
unit HRBaseClasses; interface uses SysUtils, Classes; type THRBase = class(TPersistent); THRBaseList = class(TPersistent) private FList: TList; { リスト } function GetData(Index: Integer): THRBase; { 読み込み } procedure SetData(Index: Integer; HRBase: THRBase); { 書き込み } function GetCount: Integer; { リストのカウント数 } protected procedure Error; { エラーの表示 } property List[Index: Integer]: THRBase { リストへのアクセス } read GetData write SetData; default; public constructor Create; { 生成 } destructor Destroy; override; { 破棄 } procedure Clear; { 消去 } function Add(HRBase: THRBase): Integer; { 追加 } procedure Insert(Index: Integer; HRBase: THRBase); { 挿入 } procedure Delete(Index: Integer); { 削除 } procedure Assign(Source: TPersistent); override; { Assign } published property Count: Integer read GetCount; { リストのカウント数 } end; implementation { THRBaseList } // 生成 constructor THRBaseList.Create; begin FList := TList.Create; end; // 破棄 destructor THRBaseList.Destroy; begin Clear; FList.Free; inherited Destroy; end; // 消去 procedure THRBaseList.Clear; var I: Integer; begin for I := 0 to FList.Count -1 do THRBase(FList[I]).Free; FList.Clear; end; // 追加 function THRBaseList.Add(HRBase: THRBase): Integer; begin Result := FList.Add(HRBase); end; // 挿入 procedure THRBaseList.Insert(Index: Integer; HRBase: THRBase); begin FList.Insert(Index, HRBase); end; // 削除 procedure THRBaseList.Delete(Index: Integer); begin THRBase(FList[Index]).Free; FList.Delete(Index); end; // エラー処理 procedure THRBaseList.Error; begin raise Exception.Create('インデックスがリストの範囲を超えています'); end; // リストからの取得 function THRBaseList.GetData(Index: Integer): THRBase; begin if (Index < 0) or (Index >= FList.Count) then Error; Result := THRBase(FList[Index]); end; // リストへの設定 procedure THRBaseList.SetData(Index: Integer; HRBase: THRBase); begin if (Index < 0) or (Index >= FList.Count) then Error; FList[Index] := HRBase; end; // リストのカウント数 function THRBaseList.GetCount: Integer; begin Result := FList.Count; end; // Assign procedure THRBaseList.Assign(Source: TPersistent); var I: Integer; HRBase: THRBase; begin if (Source is THRBaseList) then begin Clear; for I := 0 to (Source as THRBaseList).Count -1 do begin HRBase := THRBase.Create; HRBase.Assign((Source as THRBaseList)[I]); Add(HRBase); end; Exit; end; inherited Assign(Source); end; end.
なぜTObjectではなくて、TPersistentから継承しているのか、疑問に思われる方も多いかも知れませんね。 その理由は、私が作るリストの中では、TPersistentのAssignという仮想メソッドを再定義することが多いからです(笑)
※procedure Assign(Source: TPersistent); override; という部分ですね。
今回は、単純なクラスを拡張していくという目的で作っているので、少し回りくどい処理になっているかも知れません。 HRBaseClassesを取り込んだ形でいきなり「TListを使ったリスト No2」のMySampleClassesにあるクラスを作ることも多いです。
☆TListを使ったリスト No1
☆TListを使ったリスト No2
☆TListを使ったリスト No3
| 固定リンク