Delphi 为什么可以';我是否传递一个对象列表<;S:T>;对于需要TObjectList的函数<;T>;?
我的代码有问题,它使用泛型类型。为什么编译器不知道传递的列表(Delphi 为什么可以';我是否传递一个对象列表<;S:T>;对于需要TObjectList的函数<;T>;?,delphi,generics,tobjectlist,Delphi,Generics,Tobjectlist,我的代码有问题,它使用泛型类型。为什么编译器不知道传递的列表(Result)是TObjectList(TItem是TItems中t的类型) 接口: type TItem = class end; type IItemsLoader = interface procedure LoadAll(AList : TObjectList<TItem>); end; type TItemsLoader = class(TInterfacedObject, IItems
Result
)是TObjectList
(TItem
是TItems
中t
的类型)
接口:
type
TItem = class
end;
type
IItemsLoader = interface
procedure LoadAll(AList : TObjectList<TItem>);
end;
type
TItemsLoader = class(TInterfacedObject, IItemsLoader)
public
procedure LoadAll(AList : TObjectList<TItem>);
end;
type
IItems<T : TItem> = interface
function LoadAll : TObjectList<T>;
end;
type
TItems<T : TItem> = class(TInterfacedObject, IItems<T>)
private
FItemsLoader : TItemsLoader;
public
constructor Create;
destructor Destroy; override;
function LoadAll : TObjectList<T>;
end;
类型
TItem=类
结束;
类型
IItemsLoader=接口
程序LoadAll(列表:TObjectList);
结束;
类型
TItemsLoader=class(TInterfacedObject,IItemsLoader)
公众的
程序LoadAll(列表:TObjectList);
结束;
类型
IItems=接口
函数LoadAll:TObjectList;
结束;
类型
TItems=类别(TInterfacedObject,IItems)
私有的
FItemsLoader:TItemsLoader;
公众的
构造函数创建;
毁灭者毁灭;推翻
函数LoadAll:TObjectList;
结束;
实施:
procedure TItemsLoader.LoadAll(AList: TObjectList<TItem>);
begin
/// some stuff with AList
end;
{ TItems<T> }
constructor TItems<T>.Create;
begin
FItemsLoader := TItemsLoader.Create;
end;
destructor TItems<T>.Destroy;
begin
FItemsLoader.Free;
inherited;
end;
function TItems<T>.LoadAll: TObjectList<T>;
begin
Result := TObjectList<T>.Create();
/// Error here
/// FItemsLoader.LoadAll(Result);
end;
过程TItemsLoader.LoadAll(列表:TObjectList);
开始
///一些关于阿利斯特的东西
结束;
{TItems}
构造函数TItems.Create;
开始
FItemsLoader:=TItemsLoader.Create;
结束;
破坏分子滴度破坏;
开始
FItemsLoader.免费;
继承;
结束;
函数TItems.LoadAll:TObjectList;
开始
结果:=TObjectList.Create();
///这里出错
///FItemsLoader.LoadAll(结果);
结束;
在有错误的函数中,结果是一个TObjectList
,其中T
是TItem
的某个子类,但编译器不知道它是什么特定类。编译器必须对其进行编译,以便可以安全地运行T
的任何值。这可能与LoadAll
的参数类型不兼容,该类型需要TObjectList
,因此编译器拒绝该代码
假设T
是titemdescendat
,编译器允许错误代码编译和执行。如果LoadAll
调用AList.Add(TItem.Create)
,那么AList
将最终保存的东西不是titemdescentant
,即使它是TObjectList
。它保存的对象的类型与其泛型类型参数所表示的不同
仅仅因为S
是T
的子类型并不意味着X
是X
的子类型,您还必须使用通用版本的加载程序:
type
TItem = class
end;
type
IItemsLoader<T: TItem> = interface
procedure LoadAll(AList : TObjectList<T>);
end;
type
TItemsLoader<T: TItem> = class(TInterfacedObject, IItemsLoader<T>)
public
procedure LoadAll(AList : TObjectList<T>);
end;
type
IItems<T : TItem> = interface
function LoadAll : TObjectList<T>;
end;
type
TItems<T : TItem> = class(TInterfacedObject, IItems<T>)
private
FItemsLoader : TItemsLoader<T>;
public
constructor Create;
destructor Destroy; override;
function LoadAll : TObjectList<T>;
end;
implementation
{$R *.dfm}
procedure TItemsLoader<T>.LoadAll(AList: TObjectList<T>);
begin
/// some stuff with AList
end;
{ TItems<T> }
constructor TItems<T>.Create;
begin
FItemsLoader := TItemsLoader<T>.Create;
end;
destructor TItems<T>.Destroy;
begin
FItemsLoader.Free;
inherited;
end;
function TItems<T>.LoadAll: TObjectList<T>;
begin
Result := TObjectList<T>.Create();
/// Error here
FItemsLoader.LoadAll(Result);
end;
类型
TItem=类
结束;
类型
IItemsLoader=接口
程序LoadAll(列表:TObjectList);
结束;
类型
TItemsLoader=class(TInterfacedObject,IItemsLoader)
公众的
程序LoadAll(列表:TObjectList);
结束;
类型
IItems=接口
函数LoadAll:TObjectList;
结束;
类型
TItems=类别(TInterfacedObject,IItems)
私有的
FItemsLoader:TItemsLoader;
公众的
构造函数创建;
毁灭者毁灭;推翻
函数LoadAll:TObjectList;
结束;
实施
{$R*.dfm}
程序TItemsLoader.LoadAll(列表:TObjectList);
开始
///一些关于阿利斯特的东西
结束;
{TItems}
构造函数TItems.Create;
开始
FItemsLoader:=TItemsLoader.Create;
结束;
破坏分子滴度破坏;
开始
FItemsLoader.免费;
继承;
结束;
函数TItems.LoadAll:TObjectList;
开始
结果:=TObjectList.Create();
///这里出错
FItemsLoader.LoadAll(结果);
结束;
你说得对,我没有从这边看。你对如何重构这段代码有什么建议吗?对我来说,像LoadAll和returnresult list这样的接口很重要,或者将result list作为参数传递给TItems.LoadAll,但真正的工作是通过TItemsLoader
完成的。滴度只是间接层。TItems“知道”会有什么样的物品。TItemsLoader应该只知道,项目是TItem或其后代。我相信使用IItemsLoader
界面的另一个答案是您需要改变的。然而,罗布已经正确地解释了这一点,并回答了你的直接问题。在我的概念中,“加载器”应该只适用于TItem。但是我将尝试改变它,它将与TItem以及其他任何子类一起工作,因为泛型定义具有约束。