3

元のデータへの参照を使用して TValue を作成する方法を知っている人はいますか? 私のシリアライゼーション プロジェクトでは、( XML-Serializationで提案されているように) TValues を内部ツリー構造に格納する汎用シリアライザーを使用します (例の MemberMap に似ています)。

このメンバ ツリーは、動的セットアップ フォームを作成し、データを操作するためにも使用する必要があります。私の考えは、データのプロパティを定義することでした:

TDataModel <T> = class
  {...}
  private
    FData : TValue;
    function GetData : T;
    procedure SetData (Value : T);
  public
    property Data : T read GetData write SetData;
end;

GetData、SetData メソッドの実装:

procedure TDataModel <T>.SetData (Value : T);

begin
FData := TValue.From <T> (Value);
end;

procedure TDataModel <T>.GetData : T;

begin
Result := FData.AsType <T>;
end;

残念ながら、TValue.From メソッドは常に元のデータのコピーを作成します。したがって、アプリケーションがデータに変更を加えるたびに、DataModel は更新されません。逆に、DataModel を動的な形式で変更しても、元のデータは影響を受けません。確かに、何かを変更する前後にいつでも Data プロパティを使用できますが、DataModel 内で多くの Rtti を使用するため、いつでもこれを実行したくありません。

おそらく誰かがより良い提案をしていますか?

4

2 に答える 2

4

TValue は、あらゆる種類のデータを非常にコンパクトな形式で保持するように設計されており、「ポインタ」をエミュレートするようには設計されていません。RTTI.pas ユニットを見てください。TValue は、TValueData 型のデータ メンバを 1 つだけ持つ RECORD です。TValueData 自体がバリアント レコードです。

TValueData を見ると、最小限のデータしか保持していないことがわかります。その TValue がどこから来たのかを知る方法はありません。

解決策: 構造体に TValue を保持しないでください。TRttiField + TObject のペアに置き換えてください。TValue が必要な場合は TRttiField.GetValue(Instance) を使用し、値を設定する場合は TRttiField.SetValue(Instance, AValue:TValue) を使用します。

于 2010-05-05T12:03:36.513 に答える
0

助けてくれた Cosmin に感謝します。解決策は、TValue を構造体に保存するのではなく、データへの Pointer を使用し、フィールドまたはプロパティの GetValue メソッド、SetValue メソッドを使用することです。

したがって、ジェネリッククラスでそれを解決する方法は次のとおりです。

TDataModel <T> = class
  private
    FType     : PTypeInfo;
    FInstance : Pointer;
  public 
    constructor Create (var Data : T);
    procedure ShowContent;
  end;

constructor TDataModel <T>.Create (var Data : T);

begin
FType := TypeInfo(T);
if FType.Kind = tkClass then
  FInstance := TObject (Data)
else if FType.Kind = tkRecord then
  FInstance := @Data;
end;

procedure TDataModel <T>.ShowContent;
var 
  Ctx   : TRttiContext;
  Field : TRttiField;

begin
for Field in Ctx.GetType (FType).GetFields do
  Writeln (Field.GetValue (FInstance).ToString);
end;

これで、DataModel を介して、または元のレコード クラスを使用して、フィールドを変更できます。

于 2010-05-05T13:49:16.987 に答える