Delphi: универсальный список родовых потомков и использование универсального в качестве параметра - PullRequest
3 голосов
/ 27 октября 2009

Я немного борюсь с пониманием дженериков и того, как они могут и не могут быть использованы.

У меня есть универсальный класс TControlMediator, подобный этому:

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;

Затем я делаю «конкретные» подклассы для каждого типа элемента управления, который я хочу передать:

TEditMediator = class(TControlMediator<TEdit, string>)
public
  function GetValue: string; override;
  procedure SetValue(Value: string); override;
end;

Пока все работает нормально. Однако возникают проблемы, когда мне нужен список потомков TControlMediator или использование TControlMediator в качестве параметра метода:

TViewMediator = class
private
  FControlMediators: TList<TControlMEdiator<C, T>>;
public
  procedure registerMediator(AControlMediator: TControlMediator<C, T>);
  procedure unregisterMediator(AControlMediator: TControlMediator<C, T>);
end;

Компилятор останавливается с фатальными ошибками:

[DCC Error] mediator.pas(23): E2003 Undeclared identifier: 'C'
[DCC Error] mediator.pas(28): E2007 Constant or type identifier expected

Есть ли у кого-нибудь какие-либо подсказки о том, как это должно быть сделано?

1 Ответ

6 голосов
/ 27 октября 2009

Delphi не имеет ковариации или контравариантности по своим родовым типам. Ваши универсальные типы должны использовать фактические типы в качестве параметров. Другими словами, это:

TViewMediator = class
private
  FControlMediators: TList<TControlMEdiator<C, T>>;
public
  procedure registerMediator(AControlMediator: TControlMediator<C, T>);
  procedure unregisterMediator(AControlMediator: TControlMediator<C, T>);
end;

... не будет работать, потому что C и T не являются аргументами универсального типа для TViewMediator или фактическими типами.

TControlMediator<TEdit, string> это тип. TList<TControlMEdiator<C, T>>, когда нет типов C или T в области не является типом. Нельзя использовать заполнитель универсального типа в экземпляре универсального типа, если только эти заполнители не находятся в области видимости как аргументы универсального типа для содержащегося универсального типа или метода.

...