Delphi 如何将一组对象传递给函数进行创建?

Delphi 如何将一组对象传递给函数进行创建?,delphi,delphi-2007,variable-initialization,open-array-parameters,Delphi,Delphi 2007,Variable Initialization,Open Array Parameters,所以我在Delphi2007中工作,我正在清理我的代码。我注意到,在许多过程中,我声明了许多相同类型的不同变量 例如,我现在看到的一个过程,我声明了4个不同的字符串列表,我必须为每个列表键入var1:=TStringList.Create 我的想法是制作一个程序,它包含一个开放的变量数组,我的4个变量列表,然后创建它们。电话应该是这样的 CreateStringLists([var1,var2,var3,var4]); 但就我所知,你不能通过引用传递开放数组,因此不能做我希望做的事情。有人对此

所以我在Delphi2007中工作,我正在清理我的代码。我注意到,在许多过程中,我声明了许多相同类型的不同变量

例如,我现在看到的一个过程,我声明了4个不同的字符串列表,我必须为每个列表键入
var1:=TStringList.Create

我的想法是制作一个程序,它包含一个开放的变量数组,我的4个变量列表,然后创建它们。电话应该是这样的

CreateStringLists([var1,var2,var3,var4]);

但就我所知,你不能通过引用传递开放数组,因此不能做我希望做的事情。有人对此有什么有趣的想法吗?

您可以创建一系列带有2、3、4等参数的重载版本。例如:

procedure CreateStringLists(var L1, L2: TStringList); overload;
procedure CreateStringLists(var L1, L2, L3: TStringList); overload;
procedure CreateStringLists(var L1, L2, L3, L4: TStringList); overload;

procedure CreateStringLists(var L1, L2: TStringList);
begin
  L1 := nil;
  L2 := nil;
  Try
    L1 := TStringList.Create;
    L2 := TStringList.Create;
  Except
    FreeAndNil(L2);
    FreeAndNil(L1);
    raise;
  End;
end;

// etc.
如果我这样做,我会编写一个脚本来生成代码

另外,在我自己的代码中,我将在该函数的开头编写
InitialiseNil(L1,L2)
,并在异常处理程序中编写
FreeAndNil(L2,L1)
InitialiseNil
FreeAndNil
是由一个非常简单的Python脚本生成的函数,该脚本作为注释包含在代码库中,以便可以重新运行。像上面定义的
CreareStringLists
这样的例程只有在您有一个匹配的例程来一次性释放它们时才有用。这允许您编写:

CreateStringLists(L1, L2);
Try
  // do stuff with L1, L2
Finally
  FreeAndNil(L2, L1);
End;

最后,我并不是说我一定要这样做,但这是对这个问题的一个天真而直接的回答。正如@T.E.D.所述,这样做的需要表明代码库中存在更深层次的问题。

实际上,4个构造函数有什么问题?

在重构过程中,通常需要对代码进行非常广泛的观察。为什么要“清理”两个这样的操作,而最有可能的是你根本不应该做这些操作

在本例中,我似乎怀疑您有一个例程需要处理4个单独的字符串列表。这似乎不太可能具有良好的内聚性。也许相反,它应该是一个字符串列表处理例程,调用四次。因此,我真的希望看到整个程序,而不是评论如何使其中的一个细节更漂亮。

您可以用Delphi做任何事情(或几乎任何事情)。我不推荐使用以下代码,只是想知道这个技巧是可能的:

type
  PStringList = ^TStringList;

procedure CreateStringLists(const SL: array of PStringList);
var
  I: Integer;

begin
  for I:= 0 to High(SL) do begin
    SL[I]^:= TStringList.Create;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  SL1, SL2, SL3: TStringList;

begin
  CreateStringLists([@SL1, @SL2, @SL3]);
  SL3.Add('123');
  Caption:= SL3[0];
  SL1.Free;
  SL2.Free;
  SL3.Free;
end;

如果在您的上下文中有意义,您可以在专门的TObjectList中聚合声明

type
  TMyList<T:class,constructor> = class(TObjectList<T>)
  public
    procedure CreateItems(const ACount : integer);
  end;

procedure TMyList<T>.CreateItems(const ACount: integer);
var
  Index: Integer;
begin
  for Index := 0 to (ACount - 1) do Add(T.Create);
end;

// Test procedure
procedure TestMe;
var
  MyStringsList : TMyList<TStringList>;
begin
  MyStringsList := TMyList<TStringList>.Create(True);
  MyStringsList.CreateItems(10);
  // ...
  FreeAndNil(MyStringsList);
end;
类型
TMyList=class(TObjectList)
公众的
过程CreateItems(常量:整数);
结束;
过程TMyList.CreateItems(常量:整数);
变量
索引:整数;
开始
对于索引:=0到(ACount-1)do Add(T.Create);
结束;
//试验程序
程序测试;
变量
MyStringsList:TMyList;
开始
MyStringsList:=TMyList.Create(True);
MyStringsList.CreateItems(10);
// ...
FreeAndNil(MyStringsList);
结束;

因此,您可以专门列出您的列表。

实际上,这看起来像是一个注释,而不是一个真正的答案。从功能上看,没有什么,视觉上它会使我要查看的代码更短,并且(对我来说)更容易查看。我正在开发一些简单的演示软件,这与幻灯片(power point esq)演示特别相关。在每张幻灯片上,我有3个不同的文本区域:正文、标题、版权。然后是另一个字符串列表,用于解析文本文件中的文本,这就是幻灯片保存到磁盘的方式。它们都是为一个独特的目的而创造的。我喜欢你的回答。。。我要考虑一下。+1我怀疑我自己是否能做到这一点,但它是类型安全的,而且非常隐蔽——很好+你打败了我!我现在有了自己的基于普通指针的实现,当我注意到您的答案时,我正在升级它以使用指向TStringList的指针。:)当然,我认为,您必须在CreateStringList过程中使其具有异常意识,以便成功地创建所有异常,或者在以异常方式退出例程之前释放所有已创建的异常。@JachGrate-代码只是一个示例。若你们准备在实际项目中使用它,那个么它是可以改进的。例如,在调用构造函数之前,指针可以为零,过程可以由返回所创建对象数的函数替换,否则。@Serg:在像这样的公共场合,我赞成编写健壮的说明代码,或者至少指出如何以描述性的方式使其健壮。看看@David Heffernan对这个问题的回答。+1我会将此与Serg的解决方案结合起来:让他的一个私有,并公开您的代码,因为它更干净。