在不复制的情况下引用 Delphi 变体数组

Reference a Delphi variant array without copying

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

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^ 我只会得到一份副本。有没有办法解决?谢谢!

您正在寻找的是一个局部变量,它可以作为 reference 其他东西(特别是 Variant 数组中的一个元素) .但是,Delphi 没有提供创建 "local reference" 变量的方法。引用仅存在于作为 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;

不过,这些看起来都不是特别吸引人,特别是如果您担心仅指针访问会 "spook" 您的代码的使用者。

您提到过您希望用户将他们自己的代码合并到您生成的代码中。我不建议那样做。毕竟,在他们重新 运行 您的代码生成器之后,他们期望做什么?他们肯定会失去他们所做的任何定制。最好将生成的代码分开,最好放在单独的文件中。对于用户自定义,你可以以用户可以实现的回调函数的形式提供钩子。这样,例如,用户可以提供类似于 ModifyVariant 的内容,然后您生成的代码就可以简单地调用它。您将拥有 "Variant references," 并且生成的代码与用户代码完全分开。