How to set a forward declaration with generic types under Delphi 2010?

前端 未结 3 939
一个人的身影
一个人的身影 2020-12-01 14:39

I run into what seems to be a very classical problem: An item and a collection class, both referencing each other, that require a forward declaration. I\'m using Delphi 2010

相关标签:
3条回答
  • 2020-12-01 15:25

    You can work around it by declaring an ancestor class:

    type
      TBaseElement = class
      end;
    
      TMyCollection<T: TBaseElement> = class
      end;
    
      TMyElement = class(TBaseElement)
      private
        FParent: TMyCollection<TBaseElement>;
      end;
    
    0 讨论(0)
  • 2020-12-01 15:27

    My Collection's example (based on generics)

    type
      TMICustomItem = class(TPersistent)
      private
        FID: Variant;
        FCollection: TList<TMICustomItem>;
        function GetContained: Boolean;
      protected
        procedure SetID(Value: Integer);
      public
        constructor Create(ACollection: TList<TMICustomItem>); overload;
        constructor Create(ACollection: TList<TMICustomItem>; ID: Integer); overload;
        procedure Add; //Adding myself to parent collection
        procedure Remove; //Removing myself from parent collection        
        property Contained: Boolean read GetContained; //Check contains myself in parent collection
        property ID: Variant read FID;
      end;
    
      TMICustomCollection<ItemClass: TMICustomItem> = class(TList<ItemClass>)
      private
        function GetItemByID(ID: Integer): ItemClass;
      public
        property ItemID[ID: Integer]: ItemClass read GetItemByID; //find and return Item<ItemClass> in self by ID
      end;
    

    ...

    { TMICustomItem }
    
    constructor TMICustomItem.Create(ACollection: TList<TMICustomItem>);
    begin
      FCollection := ACollection;
    end;
    
    constructor TMICustomItem.Create(ACollection: TList<TMICustomItem>;
      ID: Integer);
    begin
      Create(ACollection);
      FID := ID;
    end;
    
    procedure TMICustomItem.Add;
    begin
      if not FCollection.Contains(Self) then
        FCollection.Add(Self)
      else
        raise EListError.CreateRes(@SGenericDuplicateItem);
    end;
    
    procedure TMICustomItem.Remove;
    begin
      if FCollection.Contains(Self) then
        FCollection.Remove(Self)
      else
        raise EListError.CreateRes(@SGenericItemNotFound);
    end;
    
    function TMICustomItem.GetContained: Boolean;
    begin
      Result := FCollection.Contains(Self);
    end;
    
    procedure TMICustomItem.SetID(Value: Integer);
    begin
      FID := Value;
    end;
    
    { TMICustomCollection<ItemClass> }
    
    function TMICustomCollection<ItemClass>.GetItemByID(ID: Integer): ItemClass;
    var
      I: Integer;
    begin
      for I := 0 to Count - 1 do
        if Items[I].ID = ID then
          Exit(Items[I]);
    
      raise EListError.CreateRes(@SGenericItemNotFound);
    end;
    
    0 讨论(0)
  • 2020-12-01 15:37

    Looks like Delphi shies away from forwarding classes related to generics.

    You may also think about creating non generic TMyCollectionBase class by moving there all code that is not dependent on the T type maybe augmenting it with some virtual functions to ideally make it all what is needed when referred by FParent. I am thinking in C++ here but it might reduce as well the size of generated code when TMyCollection is used to store items of several types.

    0 讨论(0)
提交回复
热议问题