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.
コメント