![]() |
Delphi-Version: 10 Seattle
RTTI und Generics: Set (de-)serialisieren
Hallo zusammen,
ich habe mir eine kleine generische Klasse geschrieben, mit der ich Sets in JSON Arrays umwandeln kann und umgekehrt. Da die Delphi Generics ja leider kein Constraint auf Sets zulassen, musste ich ziemlich stark mit RTTI und unsicheren Typ-Casts rumtricksen. Könnte mal jemand drüberschauen, ob es hier noch irgendwo krachen kann? Und gibt es noch Spielraum optimieren? Nicht über das
Delphi-Quellcode:
Array wundern - ich weiß, dass ich mir die String-Repräsentation der einzelnen Flags auch per RTTI holen kann, allerdings will ich in der JSON Datei gerne unabhängige (etwas einprägsamere und nicht geprefixte) Bezeichner verwenden.
ElementStrings
Delphi-Quellcode:
Viele Grüße
type
TJSONSetHelper<TSet> = record strict private class procedure GetEnumBounds(var MinValue, MaxValue: Integer); static; inline; public class function ReadValue(JSON: PJSONVariantData; const Name: String; const ElementStrings: array of String): TSet; static; class procedure WriteValue(JSON: PJSONVariantData; const Name: String; const ElementStrings: array of String; Value: TSet); static; end; class procedure TJSONSetHelper<TSet>.GetEnumBounds(var MinValue, MaxValue: Integer); var TypInfo: PTypeInfo; TypData: PTypeData; begin TypInfo := TypeInfo(TSet); {$IFDEF DEBUG} if (TypInfo^.Kind <> tkSet) then begin raise Exception.Create('Invalid generic type.'); end; {$ENDIF} TypData := GetTypeData(GetTypeData(TypInfo)^.CompType^); {$IFDEF DEBUG} if (TypData^.MinValue <> 0) then begin raise Exception.Create('The enum-type needs to be zero-based.'); end; if (TypData^.MaxValue > 255) then begin raise Exception.Create('The enum-type''s maximum value needs the be lower than 256.'); end; {$ENDIF} MinValue := TypData^.MinValue; MaxValue := TypData^.MaxValue; end; class function TJSONSetHelper<TSet>.ReadValue(JSON: PJSONVariantData; const Name: String; const ElementStrings: array of String): TSet; type TSetType = set of 0..255; var A: PJSONVariantData; MinValue, MaxValue: Integer; I, J: Integer; begin GetEnumBounds(MinValue, MaxValue); {$IFDEF DEBUG} if (MaxValue <> High(ElementStrings)) then begin raise Exception.Create('The size of the string-array does not match the size of the enum-type'); end; {$ENDIF} FillChar(Pointer(@Result)^, SizeOf(TSet), #0); A := JSON^.Data(Name); if (Assigned(A)) then begin if (A^.Kind <> jvArray) then begin raise Exception.CreateFmt('The "%s" field is not a valid JSON array.', [Name]); end; for I := 0 to A^.Count - 1 do begin for J := MinValue to MaxValue do begin if (LowerCase(A^.Item[I]) = ElementStrings[J]) then begin Include(TSetType(Pointer(@Result)^), J); Break; end; end; end; end; end; class procedure TJSONSetHelper<TSet>.WriteValue(JSON: PJSONVariantData; const Name: String; const ElementStrings: array of String; Value: TSet); type TSetType = set of 0..255; var A: TJSONVariantData; MinValue, MaxValue: Integer; I: Integer; begin GetEnumBounds(MinValue, MaxValue); {$IFDEF DEBUG} if (MaxValue <> High(ElementStrings)) then begin raise Exception.Create('The size of the string-array does not match the size of the enum-type'); end; {$ENDIF} A.Init; for I := MinValue to MaxValue do begin if (I in TSetType(Pointer(@Value)^)) then begin A.AddValue(ElementStrings[I]); end; end; if (A.Count > 0) then begin JSON^.AddNameValue(Name, Variant(A)); end; end; Zacherl |
AW: RTTI und Generics: Set (de-)serialisieren
Ich kenne mich damit zu wenig aus um zur Implementierung etwas sagen zu können, zum Design habe ich aber eine Frage:
Warum sind die Methoden alle statisch? Als Benutzer würde ich mich über etwas freuen von dem ich mir eine Instanz erstellen kann. Weiterhin könnte ich z.B. über einen Parameter im Konstruktor individuell einstellen kann ob ich die Bereichsprüfung möchte (statt dem festen IFDEF). |
AW: RTTI und Generics: Set (de-)serialisieren
Zitat:
Delphi-Quellcode:
Bräuchte lediglich Input zur Implementierung. Das generelle Design ist so schon in Ordnung für mich.
Flags := TJSONSetHelper<TMyFlags>.ReadValue(JSON, 'flags', SMyFlags))
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:21 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz