Delphi: un elenco generico di discendenti generici e che accetta un generico come parametro

StackOverflow https://stackoverflow.com/questions/1632884

  •  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?

È stato utile?

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top