2017-03-11 2 views
1

Actuellement j'ai beaucoup de dossiers avec des méthodes d'aide comme celui-ci:aide générique pour l'enregistrement

TRec1 = packed record 
    S1: string; 
    S2: string; 
    procedure FromJSON(const AJSON: string); 
    function ToJSON: string; 
end; 

procedure TRec1.FromJSON(const AJSON: string); 
begin 
    RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec1)); 
end; 

function TRec1.ToJSON: string; 
begin 
    Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec1))); 
end; 

TRec2 = packed record 
    S1: string; 
    I1: string; 
    procedure FromJSON(const AJSON: string); 
    function ToJSON: string; 
end; 

procedure TRec2.FromJSON(const AJSON: string); 
begin 
    RecordLoadJSON(Self, StringToUTF8(AJSON), TypeInfo(TRec2)); 
end; 

function TRec2.ToJSON: string; 
begin 
    Result := UTF8ToString(RecordSaveJSON(Self, TypeInfo(TRec2))); 
end; 

Comme vous pouvez le voir tous les enregistrements contiennent les mêmes méthodes toJSON et FromJSON. Cette méthode contient complètement le même code sauf TypeInfo()

N'importe quelle façon d'utiliser des génériques pour cela et ne pas décliner cette méthode pour chaque enregistrement?

+0

Vous ne pouvez pas faire cela avec un assistant. Faites une paire de fonctions pour le faire. Et BTW, l'emballage du disque ne fait pas de bien, il conduit juste à l'enregistrement étant désaligné. –

Répondre

1

Enregistrements ou classes?
Même si Delphi prend en charge les méthodes, les enregistrements sont toujours des citoyens de 2ème classe car il n'existe aucun support pour l'héritage d'enregistrements.
Les classes ont toutes les caractéristiques dont disposent les enregistrements ainsi que l'ensemble complet des fonctionnalités de POO, elles sont donc souvent un meilleur choix. Cependant, vous devez gérer la sémantique de référence qui nécessite de gérer manuellement la création et la destruction des classes sur des plates-formes non-ARC par rapport à la sémantique des valeurs sans souci des enregistrements qui ont un nettoyage automatique.

solution non génériques (en utilisant une classe)
Déclarez les conteneurs de chaîne comme un héritage de classe et de l'utilisation.

TRec1 = class(TPersistent) 
    S1: string; 
    S2: string; 
    procedure FromJSON(const AJSON: string); 
    function ToJSON: string; 
end; 

TRec2 = class(TRec1) 
end; 

procedure TRec1.FromJSON(const AJSON: string); 
begin 
    RecordLoadJSON(Self, StringToUTF8(AJSON), Self.ClassInfo); 
end; 

function TRec1.ToJSON: string; 
begin 
    Result := UTF8ToString(RecordSaveJSON(Self, Self.ClassInfo)); 
end; 

Toutes les classes héritées de TPersistent ont RTTI et donc les œuvres self.classinfo. Vous devrez peut-être modifier l'appel RecordSaveJSON en fonction de vos besoins.

solution Generics
Si vous avez RTTI activé pour votre unité {$M+} et vous devez utiliser les enregistrements, il suffit d'utiliser des méthodes en dehors de l'enregistrement et de nourrir le type d'enregistrement en tant que paramètre générique.

TRec1 = record 
    data: typex; 
    .... 
end; 

TDoJSONThings = record  //helper record for any and all types with RTTI. 
    procedure FromJSON<T:record>(var Data: T; const JSON: string); static; 
    function ToJSON<T:record>(const [ref] Data: T): string; static; 
end; 

procedure TDOJSONThings.FromJSON<T>(var Data: T; const JSON: string); static; 
var 
    pt: PTypeInfo; 
begin 
    pt:= TypeInfo(T); 
    RecordLoadJSON(Data, StringToUTF8(AJSON), pt); 
end; 

function TDOJSONThings.ToJSON<T:record>(const [ref] Data: T): string; static; 
var 
    pt: PTypeInfo; 
begin 
    pt:= TypeInfo(T); 
    Result:= UTF8ToString(RecordSaveJSON(Data, pt)); 
end; 

Remarques
L'utilisation d'un record helper (comme dans THelper = record helper for TRec1) ne fonctionnera pas, car cela ne fonctionne que pour TRec1 et les dossiers malheureusement ne prend pas en charge l'héritage.

Il aurait été préférable d'utiliser des méthodes autonomes, mais Delphi n'autorise pas les méthodes génériques qui ne font pas partie d'un enregistrement ou d'une classe.

Oh, et laissez tomber la construction de style packed record des années 1970. Cela n'a d'autre but que de ralentir votre code en le désalignant.

+0

Votre code basé sur des méthodes génériques ne peut pas fonctionner. Demandez-vous si TDoJSONThings est le même que T. Classes vs records n'est pas une décision sur la performance principalement. C'est une décision sur la valeur par rapport à la sémantique d'assignation de référence. –

+0

Oups, oui manqué la référence 'self'. – Johan

+0

Essayer de tester un échantillon avec un enregistrement: TDOJSONThings.ToJSON (R2); (R2: TRecTest2) et a obtenu l'erreur de compilateur: [erreur dcc32] E2076 Cette forme d'appel de méthode seulement autorisé pour les méthodes de classe ou constructeur Ceci est ma déclaration, qui fonctionne: TJSON = enregistrement procédure de classe De (var Data: T; const AJSON: chaîne de caractères); statique; class function & To (const [ref] Données: T): chaîne; statique; fin; –