Delphi の RTTI で record の情報取得(1/2)
Delphi 2010だったかで、機能追加された RTTI。 クラスなどのフィールド情報などを取得できる
( 2/2はこちら )
喜んで試してみたんだけど、class だけで record の情報は取得できない様子(できるのかもしれんが)
ただ、class メンバの record 型の情報は取れるので、ジェネリックスと絡めて record 型のメンバとデータを取得するクラスを作成してみた(後半のコード)
何がしたかったかというと、データ設定値などを record 型で作成して、レジストリやIniファイルへ保存するようなパターンで、フィールドが増えたときにいちいち保存や読込の所を修正しに行くのが面倒
TInifile を継承して、レコード型を渡すだけで、全て指定セクションに書き込んでちょ、みたいなのを最終的に利用できればよいと思う(SQLとのやりとりなんかにも)
Form1 に Button1 と Memo1 を貼って、TTestRecord のメンバと値を列挙する
(とりあえず String と Integer の例)
TRttiRecordField の Create で、型と実際の値を渡してやれば、あとはメソッドを呼び出すだけです
( 2/2はこちら )
喜んで試してみたんだけど、class だけで record の情報は取得できない様子(できるのかもしれんが)
ただ、class メンバの record 型の情報は取れるので、ジェネリックスと絡めて record 型のメンバとデータを取得するクラスを作成してみた(後半のコード)
何がしたかったかというと、データ設定値などを record 型で作成して、レジストリやIniファイルへ保存するようなパターンで、フィールドが増えたときにいちいち保存や読込の所を修正しに行くのが面倒
TInifile を継承して、レコード型を渡すだけで、全て指定セクションに書き込んでちょ、みたいなのを最終的に利用できればよいと思う(SQLとのやりとりなんかにも)
Form1 に Button1 と Memo1 を貼って、TTestRecord のメンバと値を列挙する
(とりあえず String と Integer の例)
TRttiRecordField の Create で、型と実際の値を渡してやれば、あとはメソッドを呼び出すだけです
type
TTestRecord = record
Key: string;
Value: Integer;
end;
procedure TForm1.Button1Click(Sender: TObject);
var I: Integer;
S: string;
RecField: TRttiRecordField<TTestRecord>;
TestRecord: TTestRecord;
begin
TestRecord.Key := 'Hello';
TestRecord.Value := 99;
RecField := TRttiRecordField<TTestRecord>.Create(TestRecord);
try
for I := RecField.Count - 1 downto 0 do begin
S := RecField.Name(I) + ' = ';
case RecField.ValueType(I) of
tkInteger:
S := S + IntToStr(RecField.Value(I).AsInteger);
tkUString:
S := S + RecField.Value(I).AsString;
end;
Memo1.Lines.Add(S);
end;
finally
RecField.Free;
end;
end;
以下 TRttiRecordField クラス (書き込みに対応したコードは、こちら)unit RttiRecordFieldUnit;
interface
uses Classes, RTTI, TypInfo;
type
TRttiRecordField<T> = class
private
FRecordData: T;
FCtx: TRttiContext;
FFields: TArray<TRttiField>;
public
constructor Create(ARecordData: T);
destructor Destroy; override;
function Count: Integer;
function ValueType(I: Integer): TTypeKind;
function Name(I: Integer): string;
function Value(I: Integer): TValue;
end;
implementation
{ TRttiRecordField<T> }
constructor TRttiRecordField<T>.Create(ARecordData: T);
begin
FRecordData := ARecordData;
FCtx := TRttiContext.Create;
FFields := FCtx.GetType(TRttiRecordField<T>).GetField('FRecordData').FieldType.GetFields;
end;
destructor TRttiRecordField<T>.Destroy;
begin
inherited;
FCtx.Free;
end;
function TRttiRecordField<T>.Count: Integer;
begin
Result := Length(FFields);
end;
function TRttiRecordField<T>.Name(I: Integer): string;
begin
Result := FFields[I].name;
end;
function TRttiRecordField<T>.ValueType(I: Integer): TTypeKind;
begin
Result := FFields[I].FieldType.TypeKind;
end;
function TRttiRecordField<T>.Value(I: Integer): TValue;
begin
Result := FFields[I].GetValue(@FRecordData);
end;
end.
コメント