微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

delphi – 将不同的记录类型作为参数传递给过程?

是否有一个技巧可以将不同类型的记录作为参数传递给过程?例如,看看这个伪代码

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;

解决方法

记录实例不包含与类相同的类型信息.因此,您需要传递一个额外的参数来指示您正在使用的类型.例如:

type
  Trecordtype = (rtPerson,rtSpider);

procedure DoSomething(recordtype: Trecordtype; const ARecord);
begin
  case recordtype of
  rtPerson:
    DoSomethingWithThisPerson(TPerson(ARecord));
  rtSpider:
    DoSomethingWithThisspider(TSpider(ARecord));
  end;
end;

您可以考虑将类型代码放在每条记录的第一个字段中:

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;

你可以使用泛型:

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;

调用这样的函数

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);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐