Skip different types of records as a parameter in a procedure?

Is there a trick to passing records with a different type as a parameter in a procedure? For example, look at this pseudocode :

type
  TPerson = record
    Species: string;
    CountLegs: Integer;
  end;

  TSpider = record
    Species: string;
    CountLegs: Integer;
    Color: TColor;
  end;

var
  APerson: TPerson;
  ASpider: TSpider;

// Is there a trick to pass different record types as parameter in a procedure?:
procedure DoSomethingWithARecord(const ARecord: TAbstractRecord?);
begin
  if ARecord is TPerson then
    DoSomethingWithThisPerson(ARecord as TPerson)
  else if ARecord is TSpider then
    DoSomethingWithThisSpider(ARecord as TSpider);
end;  

procedure DefineRecords;
begin
  APerson.Species := 'Human';
  APerson.CountLegs := 2;
  ASpider.Species := 'Insect';
  ASpider.CountLegs := 8;
  ASpider.Color := clBtnFace;
  DoSomethingWithARecord(APerson);
  DoSomethingWithARecord(ASpider);
end;
+4
source share
1 answer

Record instances do not contain type information in the same way that classes do. Therefore, you will need to pass an additional argument to indicate what type you were working with. For instance:

type
  TRecordType = (rtPerson, rtSpider);

procedure DoSomething(RecordType: TRecordType; const ARecord);
begin
  case RecordType of
  rtPerson:
    DoSomethingWithThisPerson(TPerson(ARecord));
  rtSpider:
    DoSomethingWithThisSpider(TSpider(ARecord));
  end;
end;

You might want to put the type code in the first field of each record:

type
  TPerson = record
    RecordType: TRecordType;
    Species: string;
    CountLegs: Integer;
  end;

  TSpider = record
    RecordType: TRecordType;
    Species: string;
    CountLegs: Integer;
    Color: TColor;
  end;

function GetRecordType(ARecord): TRecordType;
begin
  Result := TRecordType(ARecord);
end;

....

procedure DoSomething(const ARecord);
begin
  case GetRecordType(ARecord) of
  rtPerson:
    DoSomethingWithThisPerson(TPerson(ARecord));
  rtSpider:
    DoSomethingWithThisSpider(TSpider(ARecord));
  end;
end;

You can use generics:

type
  TMyRecordDispatcher = record
    class procedure DoSomething<T: record>(const Value: T); static;
  end;

class procedure TMyRecordDispatcher.DoSomething<T>(const Value: T); 
begin
  if TypeInfo(T) = TypeInfo(TPerson) then
    DoSomethingWithThisPerson(PPerson(@Value)^)
  else if TypeInfo(T) = TypeInfo(TSpider) then
    DoSomethingWithThisSpider(PSpider(@Value)^);
end;

And call the following functions:

TMyRecordDispatcher.DoSomething(APerson);
TMyRecordDispatcher.DoSomething(ASpider);

. . , .

, . , . . .

, , . :

DoSomethingWithThisPerson(Person);
DoSomethingWithThisSpider(Spider);

, - ?

, .

procedure DoSomething(const APerson: TPerson); overload;
begin
  ....
end;

procedure DoSomething(const ASpider: TSpider); overload;
begin
  ....
end;

....

DoSomething(Person);
DoSomething(Spider);
+9

All Articles