Нет способа указать ограничения на дженерики, так что вы можете требовать, чтобы типы были числами, поэтому вы не можете использовать числовые операторы для значений в вашем списке.Крейг Штунц написал серию постов , описывающих, как создать общую статистическую библиотеку, и он столкнулся с той же проблемой.Он решил это, предоставив дополнительные аргументы своим функциям, чтобы вызывающая сторона могла предоставить реализации для числовых операций, специфичных для типа, - шаблон шаблонный метод .Вот как он объявил операцию Average
:
type
TBinaryOp<T> = reference to function(ALeft, ARight: T): T
TStatistics<T> = class
public
class function Average(const AData: TEnumerable<T>;
AAdder, ADivider: TBinaryOp<T>;
AMapper: TFunc<integer, T>): T; overload;
Вызывающие эту функцию должны предоставить собственный код для добавления, разделения и «отображения» универсального типа.(Отображение рассматривается в следующем посте и здесь не важно.) Вы можете написать свою функцию Invert
следующим образом:
type
TUnaryOp<T> = reference to function(Arg: T): T;
TKList<T> = class
procedure Invert(ANegater: TUnaryOp<T>);
procedure TKList<T>.Invert;
var
i: Integer;
begin
for i := 0 to Pred(Count) do
Values[i] := ANegater(Values[i]);
end;
Чтобы было удобнее вызывать методы, не предоставляяВсе время добавляя дополнительные аргументы, Stuntz показал, как объявить специфический для типа потомок, предоставляющий правильные аргументы.Вы можете сделать это следующим образом:
type
TIntKList = class(TKList<Integer>)
private
class function Negate(Arg: Integer): Integer;
public
procedure Invert;
end;
procedure TIntKList.Invert;
begin
inherited Invert(Negate);
end;
Вы можете предоставить специфичные для типа потомки для общих числовых типов, и если потребители вашего класса должны использовать другие числовые типы, они могут предоставить свои собственные реализациидля базовых числовых операций без необходимости повторной реализации всего класса списка.