I have problem with my code, which uses generic types. Why doesn't the compiler know that the passed list (Result) is a TObjectList<TItem> (TItem is type for T in TItems)?
Interface:
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;
Implementation:
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;
In the function with the error,
Resultis aTObjectList<T>, whereTis some subclass ofTItem, but the compiler doesn't know what specific class it is. The compiler has to compile it so that it's safe to run for any value ofT. That might not be compatible with the argument type ofLoadAll, which requires aTObjectList<TItem>, so the compiler rejects the code.Suppose
TisTItemDescendant, and the compiler allows the faulty code to compile and execute. IfLoadAllcallsAList.Add(TItem.Create), thenAListwill end up holding something that isn't aTItemDescendant, even though it's aTObjectList<TItemDescendant>. It holds an object of a type different from what its generic type parameter says it holds.Just because
Sis a subtype ofTdoesn't mean thatX<S>is a subtype ofX<T>.