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 で、型と実際の値を渡してやれば、あとはメソッドを呼び出すだけです
以下 TRttiRecordField クラス (書き込みに対応したコードは、こちら)
( 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;
- 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.
コメント