我的代码有问题,它使用泛型类型。为什么编译器不知道传递的列表(Result
)是TObjectList<TItem>
(TItem
是T
中TItems
的类型?
接口:
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;
实现:
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;
答案 0 :(得分:4)
您还必须使用Loader的通用版本:
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;
答案 1 :(得分:3)
在带错误的函数中,Result
是TObjectList<T>
,其中T
是TItem
的某个子类,但编译器不知道它是什么特定的类是。编译器必须对其进行编译,以便可以安全地运行 T
的任何值。这可能与LoadAll
的参数类型不兼容,后者需要TObjectList<TItem>
,因此编译器会拒绝代码。
假设T
是TItemDescendant
,编译器允许编译和执行错误代码。如果LoadAll
拨打AList.Add(TItem.Create)
,那么AList
最终会收到一些不是TItemDescendant
的内容,即使它是TObjectList<TItemDescendant>
。它包含一个与其泛型类型参数所表示的类型不同的对象。
仅因为S
是T
的子类型并不意味着X<S>
是X<T>
的子类型。