Delphi: un elenco generico di discendenti generici e che accetta un generico come parametro
-
06-07-2019 - |
Domanda
Faccio un po 'fatica a comprendere i generici e come possono e non possono essere usati.
Ho un TControlMediator di classe generico come questo:
TControlMediator<C, T> = class
private
FMediatedComponent: C;
public
constructor Create(ComponentToMediate: C);
function GetValue: T; virtual; abstract;
procedure SetValue(Value: T); virtual; abstract;
property MediatedControl: C read FMediatedComponent;
end;
Realizzo quindi sottoclassi "concrete" per ogni tipo di controllo che voglio mediare:
TEditMediator = class(TControlMediator<TEdit, string>)
public
function GetValue: string; override;
procedure SetValue(Value: string); override;
end;
Finora tutto sembra funzionare bene. I problemi sorgono, tuttavia, quando voglio un elenco di discendenti di TControlMediator o prendere un TControlMediator come parametro per un metodo:
TViewMediator = class
private
FControlMediators: TList<TControlMEdiator<C, T>>;
public
procedure registerMediator(AControlMediator: TControlMediator<C, T>);
procedure unregisterMediator(AControlMediator: TControlMediator<C, T>);
end;
Il compilatore si interrompe con errori irreversibili:
[DCC Error] mediator.pas(23): E2003 Undeclared identifier: 'C'
[DCC Error] mediator.pas(28): E2007 Constant or type identifier expected
Qualcuno ha qualche indizio su come dovrebbe essere fatto?
Soluzione
Delphi non ha covarianza o contraddizione sui suoi tipi generici. I tipi generici devono utilizzare i tipi effettivi come parametri. In altre parole, questo:
TViewMediator = class
private
FControlMediators: TList<TControlMEdiator<C, T>>;
public
procedure registerMediator(AControlMediator: TControlMediator<C, T>);
procedure unregisterMediator(AControlMediator: TControlMediator<C, T>);
end;
... non funzionerà perché C e T non sono argomenti di tipo generico su TViewMediator
o tipi effettivi.
TControlMediator<TEdit, string>
è un tipo. TList<TControlMEdiator<C, T>>
, quando non ci sono tipi C
o T
nell'ambito non è un tipo. Non è possibile utilizzare un segnaposto di tipo generico in una istanza di un tipo generico a meno che tali segnaposto non rientrino nell'ambito come argomenti generici del tipo o metodo generico contenente.