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