无需复制即可引用Delphi变量数组

时间:2015-01-05 17:11:25

标签: arrays delphi pointers variant

这似乎是一个奇怪的请求,但有一个很好的理由(代码生成应用程序)。我将变量数组传递给包含在变量数组中的过程,如下所示:

TVarArray = array of variant;

procedure TMainForm.Button1Click(Sender: TObject);
var
  params: TVarArray;
  numRows: integer;
  numCols: integer;
  i: integer;
  j: integer;
begin
  SetLength(params, 2);
  numRows := 2;
  numCols := 2;

  params[0] := 5;
  params[1] := VarArrayCreate([1, numRows, 1, numCols], varVariant);
  for i := 1 to numRows do
    for j := 1 to numCols do
      params[1][i, j] := i + j;

  TestProc(params);
end;

procedure TMainForm.TestProc(params: TVarArray);
var
  arr: variant;
  p: PVariant;
  v: variant;
begin
  arr := params[1];    // -- Copies the array to arr.
  arr[2, 2] := 99;

  p := @(params[1]);
  p^[2, 2] := 88;      // -- Directly reference the passed-in array.

  v := p^;             // -- Copies the array to v -> How to prevent?
  v[2, 2] := 77;       // -- This should change the value in the original array.

  edit1.Text := VarToStr(arr[2, 2]);             // -- 99
  edit2.Text := VarToStr(params[1][2, 2]);       // -- 88  - should be 77
  edit3.Text := VarToStr(v[2, 2]);               // -- 77
end;

我不想创建数组的副本,因此可以使用p ^ []直接访问传入的数组。但是,我不想在TestProc中使用p ^语法,但更喜欢使用不带^的变量名。当然,如果我尝试v:= p ^我只是得到一份副本。有没有办法解决?谢谢!

1 个答案:

答案 0 :(得分:3)

您正在寻找的是一个局部变量,它可以充当其他东西的引用(特别是Variant数组中的元素)。但是,Delphi无法创建“本地引用”变量。引用仅存在于以varout或有时const传递的参数的上下文中。

也许您可以引入子例程并将param[1]作为var参数传递。在子例程中,您可以引用该参数,它会将数组元素作为调用者的别名。例如:

procedure ModifyVariant(var p: Variant);
begin
  p[2, 2] := 77;
end;

procedure TMainForm.TestProc(params: TVarArray);
var
  p: PVariant;
begin
  p := @params[1];

  ModifyVariant(params[1]);

  Assert(params[1][2, 2] = p^[2, 2]);
end;

ModifyVariant甚至可以是一个匿名过程,因此您可以在与调用者相同的范围内实现:

procedure TMainForm.TestProc(params: TVarArray);
var
  ModifyVariant: reference to procedure(var x: Variant);
  p: PVariant;
begin
  p := @params[1];

  ModifyVariant := procedure(var v: Variant)
  begin
    v[2, 2] := 77;
  end;

  ModifyVariant(params[1]);

  Assert(params[1][2, 2] = p^[2, 2]);
end;

但是,这些看起来都不是特别吸引人,特别是如果你害怕仅仅指针访问会“吓跑”代码的消费者。

您已经提到过,您希望您的用户将自己的代码合并到您正在生成的代码中。我不建议这样做。毕竟,他们重新运行代码生成器后他们应该做些什么呢?他们肯定会失去他们所做的任何定制。最好将生成的代码保持分离,最好是在单独的文件中。对于用户自定义,您可以以用户可以实现的回调函数的形式提供挂钩。这样,例如,用户可以提供与ModifyVariant类似的内容,然后您生成的代码可以简单地调用它。您将拥有“变体引用”,并且您将生成与用户代码完全分离的代码。