Why are TGeneric<Base> and TGeneric<Descendant> incompatible types?

我的梦境 提交于 2019-12-17 12:18:26

问题


I have started using of generics in Delphi 2010 but I have a problem when compiling this piece of code:

TThreadBase = class( TThread )
...
end;

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

TDataProviderThread = class( TThreadBase )
...
end;

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

Then I have some nested procedure:

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

And finally I want to call this nested procedure in the code of TDataCore class:

MakeAllThreadsActive(FProviders);

But compiler does not want to compile it and it says ('<>' brackets are replaced by '()'):

[DCC Error] LSCore.pas(494): E2010 Incompatible types: 'TThreadBaseList(TThreadBase)' and 'TThreadBaseList(TDataProviderThread)'

I do not understand it although TDataProviderThread is descendant of TThreadBase.

I had to fix it by hard typecasting:

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders));

Does anybody know why the compiler says this error?


回答1:


TDataProviderThread is a descendant of TThreadBase, but TThreadBaseList<TDataProviderThread> is not a descendant of TThreadBaseList<TThreadBase>. That's not inheritance, it's called covariance, and though it seems intuitively like the same thing, it isn't and it has to be supported separately. At the moment, Delphi doesn't support it, though hopefully it will in a future release.

Here's the basic reason for the covariance problem: If the function you pass it to is expecting a list of TThreadBase objects, and you pass it a list of TDataProviderThread objects, there's nothing to keep it from calling .Add and sticking some other TThreadBase object into the list that's not a TDataProviderThread, and now you've got all sorts of ugly problems. You need special tricks from the compiler to make sure this can't happen, otherwise you lose your type safety.

EDIT: Here's a possible solution for you: Make MakeAllThreadsActive into a generic method, like this:

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

Or you could do what Uwe Raabe suggested. Either one will work.




回答2:


The type

TList <TBase>

is not the parent type of

TList <TChild>

Generics can't be used that way.



来源:https://stackoverflow.com/questions/1687755/why-are-tgenericbase-and-tgenericdescendant-incompatible-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!