Recent

Author Topic: Get class fields names and assign to record fields  (Read 1024 times)

noszone

  • New Member
  • *
  • Posts: 46
Get class fields names and assign to record fields
« on: January 29, 2023, 12:18:05 pm »
I have a class:

Code: Pascal  [Select][+][-]
  1. TData = class
  2.   public
  3.     id: largeint;
  4.     name: String;
  5.     constructor Create(aID: Integer; const aName: String);
  6.   end;

I want to run a loop (or other action) in order to get fields ID and NAME of the above class. Also I have record:

Code: Pascal  [Select][+][-]
  1. DataRecord=record
  2.     id:largeint;
  3.     name:string;
  4.   end;
  5.   DataType=array of DataRecord;

In loop I want automatically assign class property to record property, like id=id, name=name.

e.g function:
for i:=0 to dataClass.fieldscount do
record[prop]=dataClass[prop]
result:=record;

So value in class.id should be written to record.id and value in class.name have to be written to record.name.

I know I can manualy assign class.id=record.id, but I want that program itself have to find names (in class and record they are identical).

Is it possible in some way? Thanks.

PascalDragon

  • Hero Member
  • *****
  • Posts: 5446
  • Compiler Developer
Re: Get class fields names and assign to record fields
« Reply #1 on: January 29, 2023, 01:20:44 pm »
Is it possible in some way? Thanks.

For the class you need to enable generation of published RTTI by putting {$M+} in front of the class and then declaring your fields not as fields, but as published properties. You can then use the RTTI units TypInfo or Rtti to access the properties.
For records there currently is no way (except of you manually knowing the order of the fields, then you can also use the RTTI which does not contain names, only offsets), but there will be once extended RTTI is implemented.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Get class fields names and assign to record fields
« Reply #2 on: January 29, 2023, 05:45:57 pm »
Wouldn't a TCollections work for that?
The only true wisdom is knowing you know nothing

cdbc

  • Hero Member
  • *****
  • Posts: 1025
    • http://www.cdbc.dk
Re: Get class fields names and assign to record fields
« Reply #3 on: January 29, 2023, 06:04:05 pm »
Hi
Something like this:
Code: Pascal  [Select][+][-]
  1. program rttitest;
  2.  
  3. uses
  4.     TypInfo;
  5.  
  6. type
  7.     TMyRec = record
  8.         p1: Integer;
  9.         p2: string;
  10.         p3: double;
  11.     end;
  12.  
  13. var
  14.     td: PTypeData;
  15.     ti: PTypeInfo;
  16.     mf: PManagedField;
  17.     p: Pointer;
  18.     f: Pointer;
  19.  
  20.     r: TMyRec;
  21.  
  22. begin
  23.     r.p1 := 312;
  24.     r.p2 := 'foo-bar';
  25.     r.p3:= 3.1459;
  26.  
  27.     ti := TypeInfo(r);
  28.     td := GetTypeData(ti);
  29.  
  30.     Writeln('Managed field count: ',td^.TotalFieldCount); // Get count of record fields
  31.  
  32.     // After ManagedFldCount TTypeData contains list of the TManagedField records
  33.     // So ...
  34.     // p := @(td^.RecInitData^.ManagedFieldCount); // Point to the ManagedFldCount ...
  35.     p := @(td^.TotalFieldCount); // Point to the ManagedFldCount ...
  36.     // Next line works for both
  37.     Inc(p, SizeOf(td^.TotalFieldCount)); // Skip it
  38.  
  39.     mf := p; { And now in the mf we have data about first record's field }
  40.     Writeln('Typeref^.Name: ',mf^.TypeRef^.Name);
  41.  
  42.     WriteLn('Value: ',r.p1); // Current value
  43.     f := @r;
  44.     Inc(f, mf^.FldOffset); // Point to the first field
  45.     Integer(f^) := 645; // Set field value
  46.     Writeln('New value: ',r.p1); // New value
  47.  
  48.     // Repeat for the second field
  49.     Inc(p, SizeOf(TManagedField));
  50.     mf := p;
  51.     Writeln('Typeref^.Name: ',mf^.TypeRef^.Name);
  52.  
  53.     WriteLn('Value: ',r.p2);
  54.     f := @r;
  55.     Inc(f, mf^.FldOffset);
  56.     string(f^) := 'abrakadabra';
  57.     Writeln('New value: ',r.p2);
  58.  
  59.     // Repeat for the third field
  60.     Inc(p, SizeOf(TManagedField));
  61.     mf := p;
  62.     Writeln('Typeref^.Name: ',mf^.TypeRef^.Name);
  63.  
  64.     WriteLn('Value: ',r.p3);
  65.     f:= @r;
  66.     Inc(f, mf^.FldOffset);
  67.     double(f^):= 7.62;
  68.     Writeln('New value: ',r.p3);
  69.     writeln('Press Enter');
  70.     Readln;
  71. end.
  72.  
... or google "rtti record stackoverflow"
Hth
Regards Benny
« Last Edit: January 29, 2023, 06:06:43 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

noszone

  • New Member
  • *
  • Posts: 46
Re: Get class fields names and assign to record fields
« Reply #4 on: January 29, 2023, 07:50:18 pm »
Thanks PascalDragon for your expertise, and others for ideas and provided code. I got a plan to use the subject in project, but after testing, seems I will use it "manually".

Could someone advise if array of objects is good idea to keep inside some huge rows data inside? I noted, for array of objects I have to each time manually create some parts of it. I guess is not the use case.

jamie

  • Hero Member
  • *****
  • Posts: 6090
Re: Get class fields names and assign to record fields
« Reply #5 on: January 29, 2023, 09:44:10 pm »
from what I can tell in your post, you are looking for the use of TCollection that manages
a TCollectionItem.

 TCollectionItem has an ID, DisplayName and a few other things in it.

you base your classes from a TCollectionItem

So with that,

 Type
    TMyClass = Class(TCollectionItem)
       your added stuff,
  End;

 And the collection.
TMyCollection := TCollection.Create(TMyClass);

 From there, as you create new items you can add them to the list..

TMyCollection.Add....

 It may not be exactly what you want but I bet it's close.

 The classes can be found in the LCL help file and online.

The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018