Pergunta

eu comecei a usar de genéricos no Delphi 2010, mas eu tenho um problema quando compilar este pedaço de código:

TThreadBase = class( TThread )
...
end;

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

TDataProviderThread = class( TThreadBase )
...
end;

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

Então eu tenho algum procedimento aninhada:

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

E, finalmente, eu quero chamar este procedimento aninhado no código de classe TDataCore:

MakeAllThreadsActive(FProviders);

Mas compilador não quer compilar-lo e ele diz ( '<>' colchetes são substituídos por '()'):

[DCC ERRO] LSCore.pas (494): tipos E2010 incompatíveis: 'TThreadBaseList (TThreadBase)' e 'TThreadBaseList (TDataProviderThread)'

Eu não entendo isso, embora TDataProviderThread é descendente de TThreadBase.

Eu tive que corrigi-lo por typecasting duro:

MakeAllThreadsActive(TThreadBaseList<TThreadBase>(FProviders));

Alguém sabe por que o compilador diz esse erro?

Foi útil?

Solução

TDataProviderThread é um descendente de TThreadBase, mas TThreadBaseList<TDataProviderThread> não é um descendente de TThreadBaseList<TThreadBase>. Isso não é herança, ele é chamado covariância , e embora pareça intuitivamente como a mesma coisa, não é e tem de ser apoiada separadamente. No momento, Delphi não apoiá-lo, embora espero que em uma versão futura.

Aqui está a razão básica para o problema covariância: Se a função de passá-lo para está esperando uma lista de TThreadBase objetos, e você passá-lo uma lista de TDataProviderThread objetos, não há nada para impedi-lo de chamar .Add e aderindo algum outro TThreadBase objeto na lista que não é um TDataProviderThread, e agora você tem todos os tipos de problemas feios. Você precisa de truques especiais do compilador para garantir que isso não pode acontecer, caso contrário, você perde o seu tipo de segurança.

EDIT: Aqui está uma solução possível para você: Faça MakeAllThreadsActive em um método genérico, como este:

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

Ou você poderia fazer o que Uwe Raabe sugeriu. Qualquer um vai trabalhar.

Outras dicas

O tipo

TList <TBase>

não é o tipo de pai

TList <TChild>

Os genéricos não pode ser usado dessa forma.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top