In many of my applications I have some data-objects which look something like this:
You can download the unit here.
This unit uses the SuperObject by Henri Gourvest
type
TMyObject = class
private
fInt: integer;
fDouble: double;
fBool: boolean;
public
property IntegerProp : integer read fInt write fInt;
property DoubleProp : double read fDouble write fDouble;
property BoolProp : boolean read fBool write fBool;
end;
Writing a SaveToFile and LoadFromFile for each is tedious work and if I change the object I have to change the two procedures as well. With Delphis support for RTTI and class helpers we can get rid of the tedious work.
I am using a class helper for TObject, so technically its possible to do this with every object.
TSerialHelper = class helper for TObject
private
function isPublicProperty(aProperty : TRttiProperty): boolean;
public
function Serialize(aHumanreadable : boolean = true) : string;
procedure Deserialize(const text : string);
end;
And here is the implementation:
function TSerialHelper.Serialize(aHumanreadable : boolean = true): string;
var
context : TRttiContext;
typ : TRttiType;
prop : TRttiProperty;
soJSON : ISuperObject;
value : TValue;
begin
context := TRttiContext.Create;
try
typ := context.GetType(self.ClassType);
soJSON := SO; // Get Superobject Interface
for prop in typ.GetProperties do
begin
if isPublicProperty(prop) and prop.IsWritable then
begin
value := prop.GetValue(self);
case value.Kind of
tkInteger, tkInt64 :
soJSON.I[prop.Name] := value.AsInteger;
tkEnumeration:
if value.IsType<boolean> then
soJSON.B[prop.Name] := value.AsBoolean;
tkFloat:
soJSON.D[prop.Name] := value.AsExtended;
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
soJSON.S[prop.Name] := value.AsString;
end;
end;
end;
result := soJSON.AsJSon(aHumanreadable);
finally
context.Free;
end;
end;
procedure TSerialHelper.Deserialize(const text: string);
var
context : TRttiContext;
typ : TRttiType;
prop : TRttiProperty;
soJSON : ISuperObject;
begin
context := TRttiContext.Create;
try
soJSON := SO(text); // Init the Superobject Interface
typ := context.GetType(self.ClassType);
for prop in typ.GetProperties do
begin
if isPublicProperty(prop) and prop.IsWritable then
begin
case prop.PropertyType.TypeKind of
tkInteger, tkInt64 :
prop.SetValue(self, TValue.From<int64>(soJSON.I[prop.Name]));
tkEnumeration:
if prop.GetValue(self).IsType<boolean> then
prop.SetValue(self, TValue.From<boolean>(soJSON.B[prop.Name]));
tkFloat:
prop.SetValue(self, TValue.From<double>(soJSON.D[prop.Name]));
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
prop.SetValue(self, TValue.From<string>(soJSON.S[prop.Name]));
end;
end;
end;
finally
context.Free;
end;
end;
function TSerialHelper.isPublicProperty(aProperty: TRttiProperty): boolean;
begin
result := aProperty.Visibility in [mvPublic, mvPublished];
end;
It is not finished, since it can't serialize sets, arrays or childobjects, but so far it works for simple objects.You can download the unit here.
This unit uses the SuperObject by Henri Gourvest
3 Kommentare:
You might want to check that the property is not read-only.
Thanks! I have updated the code.
And perhaps not a class property?
Kommentar veröffentlichen