13

我已经开始在 Delphi 2010 中使用泛型,但是在编译这段代码时遇到了问题:

TThreadBase = class( TThread )
...
end;

TThreadBaseList<T: TThreadBase> = class( TObjectList<T> )
...
end;

TDataProviderThread = class( TThreadBase )
...
end;

TDataCore = class( TInterfacedObject, IDataCore )
private
  FProviders: TThreadBaseList<TDataProviderThread>;
...
end;

然后我有一些嵌套过程:

procedure MakeAllThreadsActive(aThreads: TThreadBaseList<TThreadBase>);
begin
...
end;

最后我想在 TDataCore 类的代码中调用这个嵌套过程:

MakeAllThreadsActive(FProviders);

但是编译器不想编译它,它说('<>'括号被'()'替换):

[DCC 错误] LSCore.pas(494):E2010 不兼容的类型:“TThreadBaseList(TThreadBase)”和“TThreadBaseList(TDataProviderThread)”

虽然 TDataProviderThread 是 TThreadBase 的后代,但我不明白。

我不得不通过硬类型转换来修复它:

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders));

有谁知道为什么编译器会说这个错误?

4

2 回答 2

22

TDataProviderThread 是 TThreadBase 的后代,但TThreadBaseList<TDataProviderThread>不是TThreadBaseList<TThreadBase>. 这不是继承,它被称为covariance,虽然它在直觉上看起来像同一件事,但它不是,它必须单独支持。目前,Delphi 不支持它,但希望它会在未来的版本中支持。

这是协方差问题的基本原因:如果您传递给它的函数需要一个 TThreadBase 对象列表,并且您传递给它一个 TDataProviderThread 对象列表,那么没有什么可以阻止它调用 .Add 并将其他一些 TThreadBase 对象粘贴到其中不是 TDataProviderThread 的列表,现在你遇到了各种丑陋的问题。您需要编译器的特殊技巧来确保不会发生这种情况,否则您将失去类型安全性。

编辑:这是一个可能的解决方案:将 MakeAllThreadsActive 变成一个通用方法,如下所示:

procedure MakeAllThreadsActive<T: TThreadBase>(aThreads: TThreadBaseList<T>);

或者你可以按照 Uwe Raabe 的建议去做。任何一个都可以。

于 2009-11-06T14:02:19.703 回答
6

方式

TList <TBase>

不是的父类型

TList <TChild>

泛型不能那样使用。

于 2009-11-06T14:01:08.993 回答