Tag プロパティの真価

 何気にフラグ立てに使われている Tag プロパティ。変数代わりに使っている方が多数だと思います。Tag プロパティは TComponent を継承したコンポーネントには大抵存在します (つまり、ほぼすべてに存在する、という事です)。

 Helpには、

Tag プロパティの機能は,あらかじめ定義されていません。開発者の便宜を図るために用意されています。
Tag プロパティを使って追加の整数値を格納したり,Tag プロパティをコンポーネント参照またはポインタなどの 32 バイト値に型キャストしたりできます。

 と書かれています。重要なのは後半部分です。ポインタなどの 32 バイト値に型キャストしたり...これがミソです。"たった一つの Integer 型" ですが、一つあれば充分です。"TStringList のススメ" で書いた事に近い事ができます。

type
  TDataStruct =
    record
      Code: Integer;
      Name: String;
      DATA1: String;
      DATA2: String;
      DATA3: String;
      DATA4: String;
      DATA5: String;
    end;
  PDataStruct = ^TDataStruct;

 最初に構造体を定義しておきます。すると、

procedure TForm1.FormCreate(Sender: TObject);
var
  PDS:PDataStruct;
begin
  New(PDS);
  PDS^.Code := 123;
  PDS^.Name := 'ABC';
  { 処理 }
  Tag := Integer(PDS);
//Tag := NativeInt(PDS);
endprocedure TForm1.FormDestroy(Sender: TObject);
begin
  Dispose(PDataStruct(Pointer(Tag))); // 破棄するのを忘れずに 
end;

 このような事が可能になります。この例の場合、フォームが破棄されるまでは PDataStruct(Pointer(Tag))^.Code のような感じで構造体にアクセスできます。フォームの場合にはプロパティやグローバル変数が使えるのであまり恩恵は得られないのですが、動的に作成するコンポーネントには効果は絶大です。動的作成したコンポーネントに構造体をぶらさげておくと、動的作成したコンポーネントの削除と同時に構造体を破棄する事が可能です。

 動的作成したコンポーネントに使う構造体を TStringList や動的配列で管理しようとすると、コンポーネントの追加と削除時に非常に面倒な事になります。また、コンポーネントとそのコンポーネント用構造体の不一致が起きる場合があります。Tag プロパティを使った場合では不一致は起こり得ません。最悪の場合でもメモリリークするだけ(!)で済みます。

 XE2 以降では、Tag プロパティは NativeInt 型になりました。これにより、32bit / 64bit アプリケーションに関わらず、ポインタを型キャストして利用する事が可能となっています。


 BACK