0

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

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

我的想法是创建一个程序,该程序接受一个开放的变量数组,我的 4 个变量列表,然后将它们全部创建。电话会是这样的

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

但据我所知,您不能通过引用传递开放数组,因此不能做我希望的事情。有没有人对此有任何有趣的想法?

4

5 回答 5

5

通常在重构中,您需要对代码有一个非常广泛的看法。为什么要“清理”一些这样的操作,而您很可能根本不应该执行任何这些操作?

在这种情况下,我怀疑您有一个例程需要处理 4 个单独的字符串列表。这似乎不太可能具有良好的凝聚力。也许相反,它应该是一个调用四次的字符串列表处理例程。所以我真的很想看看整个例程,而不是评论如何让这一个更漂亮。

于 2011-01-05T20:06:44.113 回答
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;
于 2011-01-05T20:20:04.390 回答
1

您可以使用 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;

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

于 2011-01-05T20:02:56.137 回答
1

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

于 2011-01-05T20:05:03.490 回答
1

如果它在您的上下文中有意义,您可以在专门的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;

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

于 2011-01-06T10:02:35.547 回答