Delphi: универсальный список родовых потомков и использование универсального в качестве параметра
-
06-07-2019 - |
Вопрос
Я немного борюсь с пониманием дженериков и того, как они могут и не могут быть использованы.
У меня есть родовой класс 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
Есть ли у кого-нибудь какие-либо подсказки о том, как это должно быть сделано?
Решение
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
, это не тип. Заполнитель универсального типа нельзя использовать в экземпляре универсального типа, если только эти заполнители не находятся в области видимости в качестве аргументов универсального типа для содержащегося универсального типа или метода. Р>