为什么TGeneric <base />和TGeneric <descendant>不兼容类型?</descendant>

时间:2009-11-06 13:57:32

标签: delphi generics delphi-2010

我已经开始在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);

但是编译器不想编译它,它说('&lt;&gt;'括号被'()'替换):

  

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

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

我必须通过艰难的类型转换来解决它:

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders));

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

2 个答案:

答案 0 :(得分:22)

TDataProviderThread是TThreadBase的后代,但TThreadBaseList<TDataProviderThread>不是TThreadBaseList<TThreadBase>的后代。这不是继承,它被称为协方差,虽然它看起来像直观的相同,但它不是,它必须单独支持。目前,Delphi并不支持它,但希望它将来会发布。

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

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

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

或者你可以做Uwe Raabe建议的事情。任何一个都可以工作。

答案 1 :(得分:6)

类型

TList <TBase>

不是

的父类型
TList <TChild>

泛型不能以这种方式使用。