自作クラス作成Tips ー 自作クラスにレコード型のプロパティを持たせる時の注意

Delphi,Programing

自作クラスにレコードプロパティを実装したいという場面は結構あるはずです。
ただ、実装時にはいくつか注意しなければならないことがあります。

レコードプロパティのメンバに代入するときの問題

例えば次のような実装の時

  TTsrRec = record
Name  : string;
No    : Integer;
end;
TTscData = class(TObject)
private
FRec  : TTsrRec;
published
property Rec  : TTsrRec read FRec write FRec;
end;

TTscDataクラスのRecプロパティに値を書き込みたい場合、どうなるでしょうか。

procedure TForm3.FormCreate(Sender: TObject);
var
data  : TTscData;
begin
data  := TTscData.Create;
data.Rec.Name := 'Test';
data.Rec.No   := 1;
end;

実はこれ、コンパイルできません。
E2064エラーがでます。代入できないんですね。
上のような実装をした場合、これに値を書き込みたい場合はこうなります。

procedure TForm3.FormCreate(Sender: TObject);
var
data  : TTscData;
rec   : TTsrRec;
begin
rec.Name  := 'Test';
rec.No    := 1;
data  := TTscData.Create;
data.Rec  := rec;
end;

実装内容や仕様によっては、この使い方でも問題ないでしょうが
できればレコードのメンバに直接書き込みたいなと思うことも多いでしょう。
ではどうすればいいのか。

レコードを拡張すればいいんです。
Delphiのレコード型はクラス方のような実装ができます。

レコードにプロパティを用意する

レコードの実装を少々変更しました。

type
TTsrRec = record
private
FName : string;
FNo   : Integer;
procedure SetName(name:string);
procedure SetNo(no:integer);
public
property Name : string
read FName write SetName;
property No   : Integer
read FNo write SetNo;
end;
implementation
procedure TTsrRec.SetName(name:string);
begin
FName := name;
end;
procedure TTsrRec.SetNo(no:Integer);
begin
FNo := no;
end;

プロパティメソッドを実装し、レコードのメンバに書き込みをする場合はそれぞれSetName、SetNoプロシージャが呼び出されます。
このような実装をすると、レコードのメンバに直接値を書き込めるようになります。

見てのとおり、レコード型はクラスのような実装ができ、なんならイベントの実装とかも普通にできます。じゃぁ、クラスと何が違うんやというと。

  • レコードからの継承はできない
  • レコードは可変部分を持てる
  • レコードは値型、クラスは参照型
  • レコードはコンストラクタを使って自動生成されるが、クラスは明示的に生成する
  • レコードのコンストラクタはデフォルトの引数なしがあるため、ユーザー定義のコンストラクタには引数が1つ以上必要
  • レコードはデストラクタを持てない
  • 継承に対応しないので、当然virtualやdynamicなんかもサポートしない。
  • レコードはWin32プラットフォームでインターフェースを実装できない

と、こんなところです。
特に継承できるのか否かは大きいと思います。
なので、どちらで実装するかはケースバイケースでって感じで。

Delphi,Programing

Posted by tsubakurame