Search code examples
arraysdelphivariant

How to convert a Variant (containing an array) to an array, to pass it as a parameter?


I need to call a function expecting an array of Integer, but I have my values in a variable of type Variant, containing the array.

Do I really have to copy the values in a loop? I couldn't find a better way that works.

The same variant can also hold a single Integer instead of the array, so I created a helper function allowing both (checking with VarIsArray). It works, but it is just lengthy and not nice :)

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;

I'm using Delphi 10.2.2 and the function to be called cannot be changed and looks like this:

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

Solution

  • Fortunately there is no need for a loop, at least when the array is 0-based.

    If the called function would expect a dynamic array, you could just pass the Variant as it is. You can also directly assign it to a dynamic array variable.

    In your case it is an open array parameter, and that needs casting in this case.

    Here is some demonstration of what is possible and how, including a nice and short helper function allowing both arrays and single values.

    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.