为什么我不能将TObjectList <s:t =“”>传递给期望TObjectList <t>的函数?</t> </s:>

时间:2012-04-27 16:47:31

标签: delphi generics tobjectlist

我的代码有问题,它使用泛型类型。为什么编译器不知道传递的列表(Result)是TObjectList<TItem>TItemTTItems的类型?

接口:

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;

2 个答案:

答案 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)

在带错误的函数中,ResultTObjectList<T>,其中TTItem的某个子类,但编译器不知道它是什么特定的类是。编译器必须对其进行编译,以便可以安全地运行 T的任何值。这可能与LoadAll的参数类型不兼容,后者需要TObjectList<TItem>,因此编译器会拒绝代码。

假设TTItemDescendant,编译器允许编译和执行错误代码。如果LoadAll拨打AList.Add(TItem.Create),那么AList最终会收到一些不是TItemDescendant的内容,即使它是TObjectList<TItemDescendant>。它包含一个与其泛型类型参数所表示的类型不同的对象。

仅因为ST的子类型并不意味着X<S>X<T>的子类型。