在Delphi 10 Seattle中,我想制作具有如下结构的TProject类:
// TProject
// Frames[]:TFrame -- all frames in project folder
// Sounds[]:TSound -- all sounds in project folder
// WorkSets[]:TWorkSet -- frames subsets for some kind of works
// WorkSetFrames[]:TWorkSetFrame
// Clips[]:TClip -- recorded clips
// ClipFrames[]:TClipFrame
我想要的不仅仅是从项目到集合以及从集合到项目的前向链接。此外,我希望从每个最终项目到其拥有的集合以及从每个集合到其所有者对象的反向链接。
主要请求 - 必须正确输入所有链接:
它必须由构造函数填充并从该基本泛型类中获取。
接下来 - 它必须是可覆盖的,允许我将属性Name添加到泛型集合项后代和FindByName函数到泛型集合类,并获得从这两个新泛型类实例化我的一些集合的可能性。例如,使用此功能制作TFrame和TFrameCollection。
它可以基于TCollection或TList,但它们都没有所有必需的功能。
我尝试了一些声明,但是导致了类不兼容错误(解释中提到了https://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29问题)。
UPD 1:
最后一次尝试解决使用泛型集合和泛型集合项的问题,它们互相使用并允许覆盖它,这使我得到了这段代码:
unit GenericCollection;
interface
uses Generics.Collections;
type
TGenericCollectionItem<TCollectionOwner: class> = class
public
type
TCollection = class(TList<TGenericCollectionItem<TCollectionOwner>>)
private
FOwner: TCollectionOwner;
public
property Owner: TCollectionOwner read FOwner;
constructor Create(AOwner: TCollectionOwner);
end;
private
FOwnerCollection: TCollection;
function GetIndex: Integer;
procedure SetIndex(const Value: Integer);
public
property Index: Integer read GetIndex write SetIndex;
property OwnerCollection: TCollection read FOwnerCollection;
end;
TNamedGenericCollectionItem<TCollectionOwner: class> = class(TGenericCollectionItem<TCollectionOwner>)
public
type
TNamedGenericCollection = class(TCollection)
public
function FindItemName(AName: string): TNamedGenericCollectionItem<TCollectionOwner>;
end;
private
FName: string;
public
property Name: string read FName write FName;
end;
implementation
{ TGenericCollectionItem<ACollectionOwnerType> }
function TGenericCollectionItem<TCollectionOwner>.GetIndex: Integer;
begin
Result := OwnerCollection.IndexOf(Self);
end;
procedure TGenericCollectionItem<TCollectionOwner>.SetIndex(
const Value: Integer);
var
CurIndex: Integer;
begin
CurIndex := GetIndex;
if (CurIndex >= 0) and (CurIndex <> Value) then
FOwnerCollection.Move(CurIndex, Value);
end;
{ TGenericCollectionItem<ACollectionOwnerType>.TCollection }
constructor TGenericCollectionItem<TCollectionOwner>.TCollection.Create(
AOwner: TCollectionOwner);
begin
inherited Create;
FOwner := AOwner;
end;
{ TNamedGenericCollectionItem<TCollectionOwner>.TNamedGenericCollection }
function TNamedGenericCollectionItem<TCollectionOwner>.TNamedGenericCollection.FindItemName(
AName: string): TNamedGenericCollectionItem<TCollectionOwner>;
var
X: TGenericCollectionItem<TCollectionOwner>;
begin
// TODO: Use hash-based index
for X in Self do
if TNamedGenericCollectionItem<TCollectionOwner>(X).Name = AName then
Exit(TNamedGenericCollectionItem<TCollectionOwner>(X));
end;
end.
但是当我通过声明
来使用它时 TFrame = class(TNamedGenericCollectionItem<TProject>)
end;
并添加到TProject
FFrames: TFrame.TNamedGenericCollection;
TProject构造函数中的这个调用
FFrames := TFrame.TNamedGenericCollection.Create(Self);
仍然令我恼火的例外:
[dcc32 Error] ProjectInfo.pas(109): E2010 Incompatible types:
'TNamedGenericCollectionItem<TCollectionOwner>.TNamedGenericCollection' and
'GenericCollection.TNamedGenericCollectionItem<ProjectInfo.TProject>.TNamedGenericCollection'
我能做些什么来解决这个问题?
答案 0 :(得分:1)
我真的认为你过分思考这一点。一旦我了解了你想要做的事情,你只需要拥有者知道它的项目是什么(例如,TObjectList&lt; T&gt; T已经知道),并且项目知道它的拥有者是什么,这是容易建造。
#div-to-contain-image img {
display: block;
height: 100%;
width: 100%;
}
要将其扩展到后代,如果所有者没有更改,这对于项目来说就足够了。但确实如此。但是,我们需要做的就是使用泛型来向后代反映所有者如何更改 - 比如
unit Unitgenerics;
interface
uses
System.Generics.Collections;
type
TGItem<TOwner : class> = class
private
fOwner: TOwner;
public
constructor Create( const pOwner : TOwner );
property Owner : TOwner
read fOwner;
end;
TRealItem = class;
TRealOwner = class( TObjectList<TRealItem> )
// Items are already of type TRealItem
end;
TRealItem = class(TGItem< TRealOwner > )
// Owner already defined and is of type TRealOwner
end;
implementation
{ TGItem<TOwner> }
constructor TGItem<TOwner>.Create(const pOwner: TOwner);
begin
inherited Create;
fOwner := pOwner;
end;
end.
这是如何在没有嵌套泛型的情况下进一步扩展......
unit Unitgenerics;
interface
uses
System.Generics.Collections;
type
TGItem<TOwner : class> = class
private
fOwner: TOwner;
public
constructor Create( const pOwner : TOwner );
property Owner : TOwner
read fOwner;
end;
TRealItem< TOwner : class > = class;
TRealOwner<TOwner : class> = class( TObjectList<TRealItem< TOwner >> )
// Items are already of type TRealItem<TOwner>
end;
TRealItem< TOwner : class > = class(TGItem< TRealOwner<TOwner> > )
// Owner already defined and is of type TRealOwner<TOwner>
end;
implementation
{ TGItem<TOwner> }
constructor TGItem<TOwner>.Create(const pOwner: TOwner);
begin
inherited Create;
fOwner := pOwner;
end;
end.
我使用我的原则更新了您的示例。在这个过程中,我意识到你的主要问题是处理事实上顶级项目实际上是一个列表。您正在尝试使用复杂的构造向编译器解释这一点,但这不是实现它的方法。
unit Unitgenerics;
interface
uses
System.Generics.Collections;
type
TGItem<TOwner : class> = class
private
fOwner: TOwner;
public
constructor Create( const pOwner : TOwner );
property Owner : TOwner
read fOwner;
end;
TRealItem< TOwner : class > = class;
TRealOwner<TOwner : class> = class( TObjectList<TRealItem< TOwner >> )
// Items are already of type TRealItem
// add some properties here
end;
TRealItem< TOwner : class > = class(TGItem< TRealOwner<TOwner> > )
// Owner already defined and is of type TRealOwner
// add some properties here
end;
T2ndLevelItem = class;
T2ndLevelOwner = class;
T2ndLevelOwner = class( TRealOwner< T2ndLevelOwner > )
end;
T2ndLevelItem = class( TRealItem< T2ndLevelOwner > )
end;
TInheritable2ndLevelItem< TOwner : class> = class;
TInheritable2ndLevelOwner< TOwner : class> = class;
TInheritable2ndLevelOwner< TOwner : class> = class( TRealOwner< TOwner > )
end;
TInheritable2ndLevelItem< TOwner : class> = class( TRealItem< TOwner > )
end;
T3rdLevelItem = class;
T3rdLevelOwner = class;
T3rdLevelOwner = class( TRealOwner< T3rdLevelOwner > )
end;
T3rdLevelItem = class( TRealItem< T3rdLevelOwner > )
end;
TInheritable3rdLevelItem< TOwner : class> = class;
TInheritable3rdLevelOwner< TOwner : class> = class;
TInheritable3rdLevelOwner< TOwner : class> = class( TInheritable2ndLevelOwner< TOwner > )
end;
TInheritable3rdLevelItem< TOwner : class> = class( TInheritable2ndLevelItem< TOwner > )
end;
implementation
{ TGItem<TOwner> }
constructor TGItem<TOwner>.Create(const pOwner: TOwner);
begin
inherited Create;
fOwner := pOwner;
end;
end.
我希望这会有所帮助。