Rtti Data Processing and Data Consistency in Delphi 2010

Does anyone have an idea how I can make TValue using the link to the source data? In my serialization project, I use (as suggested in XML-Serialization ) a generic serializer that stores TValues ​​in an internal tree structure (similar to MemberMap in the example).

This tree of elements should also be used to create a form of dynamic configuration and data management. My idea was to define a property for the data:

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

Implementation of GetData, SetData methods:

 procedure TDataModel <T>.SetData (Value : T); begin FData := TValue.From <T> (Value); end; procedure TDataModel <T>.GetData : T; begin Result := FData.AsType <T>; end; 

Unfortunately, the TValue.From method always makes a copy of the source data. Therefore, whenever the application makes changes to the data, the DataModel is not updated, and vice versa, if I change my DataModel in a dynamic form, the original data will not be affected. Of course, I could always use the Data property before and after changing something, but since I use a lot of Rtti inside my DataModel, I don’t want to do this at any time.

Maybe someone has a better deal?

+3
rtti delphi delphi-2010 tvalue
source share
2 answers

A TValue is designed to store any data in a very compact form, not intended to emulate a "pointer". Take a look at the RTTI.pas module: TValue is a record that has only one data item of type TValueData. TValueData itself is a recording option.

Looking at TValueData, you will see how it does NOT store anything but a minimal amount of data. It is impossible to know where this TValue came from.

Decision. Do not keep TValue in your structures, replace it with a pair of TRttiField + TObject. When you need TValue, use TRttiField.GetValue (Instance), when you want to set a value, use TRttiField.SetValue (Instance, AValue: TValue).

+4
source share

Thanks Cosmin for your help, the solution is not to save the TValue in the structure, but to use a pointer to the data and use the GetValue, SetValue methods for the field or property.

So, here is how I solved it in my generic class:

 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; 

Now you can either change the fields using the DataModel, or using the source record class.

0
source share

All Articles