代码之家  ›  专栏  ›  技术社区  ›  user1580348

在过程中传递不同的记录类型作为参数?

  •  4
  • user1580348  · 技术社区  · 9 年前

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

    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;
    
    1 回复  |  直到 9 年前
        1
  •  8
  •   David Heffernan    9 年前

    记录实例不像类那样包含类型信息。因此您需要传递一个额外的参数来指示您使用的类型。例如:

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