Pepito Gomiz
Pepito Gomiz

Reputation: 59

Operations with record in Delphi

I have the following code

type
  TEnumTest = (
   Hello1 = 0,
   Hello2 = 1,
   Hello3 = 2,
   Hello4 = 3,
   Hello5 = 4
);

type
   TRecordTest1 = record
       testa : Integer;
       testb : AnsiString;
       testc : Boolean;
       testd : LongWord;
end;

type
   TRecordTest2 = record
       testa : Integer;
       testb : AnsiString;
       testc : Boolean;
       testd : TEnumTest;
end;

type
   TRecordTest3 = record
       testa : Integer;
       testb : AnsiString;
       testc : Boolean;
       testd : TEnumTest;
end;

type
   TRecordTest4 = record
       testa : Integer;
       testb : AnsiString;
       testc : Boolean;
       testd : TEnumTest;
end;

type 
    TtestRecord = record
      test1 : TRecordTest1;
      test2 : TRecordTest2;
      test3 : TRecordTest3;
      test4 : TRecordTest4;
end; 

Is there a way by using reflection or other mechanism so I can do operations such as:

var
  a : TtestRecord;
  b : TtestRecord;
if a = b then
begin
  ..............
  ..............
end;
clearAllValues(a);

I just added the logical expression

Upvotes: 2

Views: 1637

Answers (3)

Remy Lebeau
Remy Lebeau

Reputation: 596196

The compiler knows how to assign one record to another, so you don't need to do anything special for that. On the other hand, if you want to compare records, you have to implement that manually.

For clearing a record in a general manner, that can be done in Delphi 2010+ using Extended RTTI. But it would be a lot of manual coding. The compiler already knows how to initialize a record, especially when it contains any compiler-managed types, like strings. Let the compiler utilize that reflection for you, eg:

var
  a : TtestRecord;
  b : TtestRecord;
begin
  a := b;
  a := Default(TtestRecord);
end;

Upvotes: 1

Arnaud Bouchez
Arnaud Bouchez

Reputation: 43033

You can use the Record*() functions, available in our Open Source SynCommons.pas unit.

You would be able to write:

var
  a : TtestRecord;
  b : TtestRecord;
...
  if RecordEquals(a,b,TypeInfo(TtestRecord)) then 
    writeln('a=b');
  RecordClear(a,TypeInfo(TtestRecord));
...

You have a lot of additional functions, like fast binary or JSON serialization.

var tmp: RawByteString;
    json: RawUTF8;
...
  tmp := RecordSave(a,TypeInfo(TtestRecord));
...
  RecordLoad(b,pointer(tmp),TypeInfo(TtestRecord));
...
  json := RecordSaveJSON(a,TypeInfo(TtestRecord));
  RecordLoadJSON(b,pointer(json),TypeInfo(TtestRecord));
...

Since Delphi 2010, the JSON serialization will use advanced RTTI. Before Delphi 2010, you just have to register the type using some text.

So this features works from Delphi 6 up to XE8, and also with FreePascal.

As reference, take a look at the corresponding documentation of our framework.

Upvotes: 0

David Heffernan
David Heffernan

Reputation: 612954

Comparing two records for equality

You could certainly use RTTI to perform comparisons of records. However, I think I would do that by using extended records with comparison operators. For instance:

type
  TMyRecord = record
    i: Integer;
    s: string;
    class operator Equal(const lhs, rhs: TMyRecord): Boolean;
    class operator NotEqual(const lhs, rhs: TMyRecord): Boolean;
  end;

class operator TMyRecord.Equal(const lhs, rhs: TMyRecord): Boolean;
begin
  Result := (lhs.i = rhs.i) and (lhs.s = rhs.s);
end;

class operator TMyRecord.NotEqual(const lhs, rhs: TMyRecord): Boolean;
begin
  Result := not (lhs = rhs);
end;

Clearing a record

You can use the intrinsic function Default to default initialize any type. I'd include a documentation link, but this function is, sadly, undocumented.

You would write your code like this:

var
  a: TTestRecord;
...
a := Default(TTestRecord); // a is replaced with default initialized value

The undocumented Default function takes a type identifier as its argument, and returns a default initialized instance of that type. So, numeric types are initialized to zero, strings to '', pointers to nil, etc.

Upvotes: 4

Related Questions