English 中文(简体)
Why are TGeneric<Base> and TGeneric<Descendant> incompatible types?
原标题:

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?

最佳回答

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.

问题回答

The type

TList <TBase>

is not the parent type of

TList <TChild>

Generics can t be used that way.





相关问题
determining the character set to use

my delphi 2009 app has a basic translation system that uses GNUGetText. i had used some win API calls to prepare the fonts. i thought it was working correctly until recently when someone from Malta ...

Help with strange Delphi 5 IDE problems

Ok, I m going nuts here. For the last (almost) four years, I ve been putting up with some extremely bad behavior from my Delphi 5 IDE. Problems include: Seemingly random errors in coride50.bpl ...

How to write a Remote DataModule to run on a linux server?

i would like to know if there are any solution to do this. Does anyone? The big picture: I want to access data over the web, using my delphi thin clients. But i´would like to keep my server/service ...

How convert string to integer in Oxygene

In Delphi, there is a function StrToInt() that converts a string to an integer value; there is also IntToStr(), which does the reverse. These functions doesn t appear to be part of Oxygene, and I can ...

Quick padding of a string in Delphi

I was trying to speed up a certain routine in an application, and my profiler, AQTime, identified one method in particular as a bottleneck. The method has been with us for years, and is part of a "...

热门标签