这是我基于 Delphi 泛型的单元 Zoomicon.Collections 的摘录:
uses System.Rtti; //for RttiContext
//...
type
TListEx<T> = class(TList<T>)
//...
{ForEach}
class procedure ForEach(const Enum: TEnumerable<T>; const Proc: TProc<T>; const Predicate: TPredicate<T> = nil); overload;
procedure ForEach(const Proc: TProc<T>; const Predicate: TPredicate<T> = nil); overload;
end;
//...
{$region 'ForEach'}
class procedure TListEx<T>.ForEach(const Enum: TEnumerable<T>; const Proc: TProc<T>; const Predicate: TPredicate<T> = nil);
begin
if Assigned(Proc) then
for var item in Enum do
if (not Assigned(Predicate)) or Predicate(item) then
Proc(item);
end;
procedure TListEx<T>.ForEach(const Proc: TProc<T>; const Predicate: TPredicate<T> = nil);
begin
{TListEx<T>.}ForEach(self, Proc, Predicate);
end;
{$endregion}
尝试使用匿名方法,以便您可以捕获上下文并传递给您作为引用传递的 TProc(因为它只接受 T)。以DX、DY为例,见下文:
type
Manipulator = class(TFrame)
pubic
class procedure MoveControls(const Controls: TControlList; const DX, DY: Single); overload;
procedure MoveControls(const DX, DY: Single); overload;
end;
class procedure TManipulator.MoveControls(const Controls: TControlList; const DX, DY: Single);
begin
if (DX <> 0) or (DY <> 0) then
TListEx<TControl>.ForEach(Controls,
procedure (Control: TControl)
begin
with Control.Position do
Point := Point + TPointF.Create(DX, DY);
end
);
end;
procedure TManipulator.MoveControls(const DX, DY: Single);
begin
if (DX <> 0) or (DY <> 0) then
begin
BeginUpdate;
MoveControls(Controls, DX, DY);
EndUpdate;
end;
end;
myManipulator.MoveControls(20, 20);
您可以在那里找到更高级的版本,它们还可以将集合中的项目转换为您需要的类:
TObjectListEx<TControl>.ForEachClass<TButton>(Controls, SomeProc);
与执行以下操作相比,这是一种优化(因为它不构造中间列表):
var list := TObjectListEx<TControl>.GetAllClass<TButton>(Controls);
list.ForEach(SomeProc);
FreeAndNil(list);
目前在我正在开发的应用程序的存储库中:
https://github.com/Zoomicon/READCOM_App/tree/master/Zoomicon.Generics/Collections(未来可能会移至自己的存储库)