如何将Variant(包含数组)转换为数组,将其作为参数传递?

时间:2018-03-26 19:18:49

标签: arrays delphi variant

我需要调用一个期望array of Integer的函数,但我的值在Variant类型的变量中,包含数组。

我真的必须在循环中复制值吗?我找不到更好的方法。

相同的变体也可以包含单个Integer而不是数组,因此我创建了一个辅助函数,允许两者(使用VarIsArray检查)。它有效,但它只是冗长而不好:)

type
  TIntegerArray = array of Integer;

function VarToArrayInt(const V: Variant): TIntegerArray;
var
  I: Integer;
begin
  if VarIsArray(V) then begin
    SetLength(Result, VarArrayHighBound(V, 1) + 1);
    for I:= 0 to High(Result) do Result[I]:= V[I];
  end else begin
    SetLength(Result, 1);
    Result[0]:= V;
  end;
end;

我正在使用Delphi 10.2.2并且无法更改要调用的函数,如下所示:

function Work(Otherparameters; const AParams: array of Integer): Boolean;

2 个答案:

答案 0 :(得分:4)

如果函数将array of Integer作为单独的类型,例如:

type
  TIntegerArray = array of Integer;

function DoIt(const Values: TIntegerArray): ReturnType;

然后该函数将Dynamic Array作为输入。您可以将保持数组的Variant分配/传递给动态数组变量/参数。编译器非常智能,可以调用RTL的VarToDynArray()函数来分配一个具有Variant数组元素副本的新动态数组。在没有复制数组数据的情况下,无法将Variant数组传递给动态数组。

但是,如果函数直接在其参数列表中使用array of Integer,例如:

function DoIt(const Values: array of Integer): ReturnType;

然后输入Open Array

  

可以通过显式传递两个参数来调用具有开放数组参数的Delphi函数:

     
      
  • 指向数组第一个元素的指针
  •   
  • 计数,即最后一个索引的值(即数组元素的大小/数量减一)"
  •   

您无法将Variant(无论是否包含数组)直接传递给Open Array参数。编译器不够智能,无法提取数组指针和元素计数,并将它们传递给Open Array参数。但是,您可以使用一些类型的技巧手动完成,例如:

function DoIt(const Values: array of Integer): ReturnType;

...

type
  TOpenArrayFunc = function(const Values: PInteger; ValuesHigh: Integer): ReturnType;

var
  V: Variant;
  Count: Integer;
  P: PInteger;
begin
  ...
  V := ...;
  Count := VarArrayHighBound(V, 1) - VarArrayLowBound(V, 1) + 1;
  P := VarArrayLock(V);
  try
    TOpenArrayFunc(@DoIt)(P, Count-1);
  finally
    VarArrayUnlock(V);
  end;
  ...
end;

这会将Variant数组直接传递给函数,而根本不会复制数组元素。

答案 1 :(得分:0)

幸运的是,不需要循环,至少在数组是从0开始的时候。

如果被调用的函数需要动态数组,则可以按原样传递Variant。您也可以直接将其分配给动态数组变量。

在你的情况下,它是一个开放的数组参数,在这种情况下需要转换。

以下是一些可能的以及如何实现的演示,包括允许数组和单个值的良好和简短的辅助函数。

program Test;

uses Variants;

procedure PrintOpenArray(const Arr: array of Integer); {open array parameter}
var
  I: Integer;
begin
  for I in Arr do Writeln(I);
end;

procedure PrintDynamicArray(const Arr: TArray<Integer>); {dynamic array param}
begin
  PrintOpenArray(Arr);
end;

function VarToArrayInt(const V: Variant): TArray<Integer>;
begin
  if VarIsArray(V) then Result:= V else Result:= [V];
  {[V] works only in XE7 and up. You can use TArray<Integer>.Create(V) instead}
end;

type  {dynamic integer array, but only compatible to this type}
  TIntegerArray = array of Integer;

var
  V: Variant;
  A: TArray<Integer>; {dynamic array, compatible to any other TArray<Integer>}
begin {all the following only works with 0-based arrays!}
  V:= VarArrayCreate([0, 2], varInteger);
  V[0]:= 1;
  V[1]:= 2;
  V[2]:= 3;

  A:= V; {Variant can just be assigned to dynamic array if it contains an array}
  PrintOpenArray(A);

  PrintDynamicArray(V); {works directly without casting}
  PrintOpenArray(TArray<Integer>(V)); {not possible without casting}
  PrintOpenArray(TIntegerArray(V));
  PrintOpenArray(VarToArrayInt(V));

  V:= 4; {demonstration of helper function to allow arrays and single values}
  PrintOpenArray(VarToArrayInt(V));
  PrintDynamicArray(VarToArrayInt(V));

  Readln;
end.