¿Cómo establecer una statement directa con tipos generics en Delphi 2010?

Me encuentro con lo que parece ser un problema muy clásico: un elemento y una clase de colección, ambos haciendo referencia entre sí, que requieren una statement directa. Estoy usando Delphi 2010 con la actualización 5.

Esto funciona bien con clases no genéricas pero no puedo solucionar el error E2086 con tipos generics:

type // Forward declarations TMyElement = class; // E2086: Type 'TMyElement' is not yet completely defined TMyCollection = class // end; TMyElement = class FParent: TMyCollection; end; 

El mismo problema ocurre al cambiar el orden de statement de clase.

No encontré ninguna referencia a este problema aquí ni en QualityCentral (se encontraron otros problemas con E2086, pero no relacionados con este caso de uso)

La única solución que tengo ahora es declarar al padre como TObject, y convertirlo al tipo genérico de la colección cuando sea necesario (no una solución limpia …)

¿Cómo resolvió este problema o reenvió sus clases genéricas?

Gracias,

[Editar 22 de octubre de 2011] Seguimiento en QualityCentral: Informé este error en calidad central aquí

Esto ha sido cerrado recientemente por EMB con el siguiente estado de resolución: Resolución: según diseño Resuelto en la comstackción: 16.0.4152

Solo tengo Delphi 2010. ¿Podría alguien confirmar que se ha corregido en Delphe XE2 Update1, o significa que funciona “como se esperaba”?

[Edición 23 de octubre de 2011] Respuesta final de EMB: EMB confirmó hoy que el comstackdor real de Delphi no admite el uso de la statement directa de un tipo genérico. Puede ver su respuesta en QC, con el enlace proporcionado anteriormente.

Puede solucionarlo declarando una clase ancestra:

 type TBaseElement = class end; TMyCollection = class end; TMyElement = class(TBaseElement) private FParent: TMyCollection; end; 

Parece que Delphi evita las clases relacionadas con generics.

También puede pensar en crear una clase TMyCollectionBase no genérica moviendo allí todo el código que no depende del tipo T, tal vez aumentándolo con algunas funciones virtuales para, idealmente, convertirlo en todo lo que se necesita cuando se lo menciona FParent. Estoy pensando en C ++ aquí, pero también podría reducir el tamaño del código generado cuando TMyCollection se utiliza para almacenar elementos de varios tipos.

El ejemplo de mi colección (basado en generics)

 type TMICustomItem = class(TPersistent) private FID: Variant; FCollection: TList; function GetContained: Boolean; protected procedure SetID(Value: Integer); public constructor Create(ACollection: TList); overload; constructor Create(ACollection: TList; 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 = class(TList) private function GetItemByID(ID: Integer): ItemClass; public property ItemID[ID: Integer]: ItemClass read GetItemByID; //find and return Item in self by ID end; 

 { TMICustomItem } constructor TMICustomItem.Create(ACollection: TList); begin FCollection := ACollection; end; constructor TMICustomItem.Create(ACollection: TList; 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 } function TMICustomCollection.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;