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 是一个 RECORD,它只有一个 TValueData 类型的数据成员。TValueData 本身就是一个变体记录。

查看 TValueData,您会发现它只包含最少的数据量:无法知道 TValue 的来源。

解决方案:不要在结构中保存 TValue,将其替换为一对 TRttiField + 一个 TObject。当你需要 TValue 时使用 TRttiField.GetValue(Instance),当你想设置一个值时使用 TRttiField.SetValue(Instance, AValue:TValue)。

于 2010-05-05T12:03:36.513 回答
0

感谢 Cosmin 的帮助,解决方案不是在结构中保存 TValue,而是使用指向数据的指针并使用字段或属性的 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 回答