如何将 Variant(包含数组)转换为数组,并将其作为参数传递?
How to convert a Variant (containing an array) to an array, to pass it as a parameter?
我需要调用一个需要 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;
幸运的是不需要循环,至少当数组从 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.
如果函数将array of Integer
作为单独的类型,例如:
type
TIntegerArray = array of Integer;
function DoIt(const Values: TIntegerArray): ReturnType;
然后函数将 Dynamic Array 作为输入。你可以assign/pass一个Variant
持有一个数组到一个动态数组variable/parameter。编译器足够聪明,可以调用 RTL 的 VarToDynArray()
函数来分配一个新的动态数组,该数组具有 Variant
的数组元素的副本。如果不复制数组数据,就无法将包含数组的 Variant
传递给动态数组。
然而,如果函数在其参数列表中直接采用 array of Integer
,例如:
function DoIt(const Values: array of Integer): ReturnType;
然后它需要一个 Open Array 作为输入:
an Delphi function that has an open array parameter can be called by explicitly passing two parameters:
- A pointer to the first element of the array
- A count, which is the value of the last index (that is, the size/number of array elements, minus one)"
您不能将 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
的数组直接传递给函数,根本不会复制数组元素。
我需要调用一个需要 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;
幸运的是不需要循环,至少当数组从 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.
如果函数将array of Integer
作为单独的类型,例如:
type
TIntegerArray = array of Integer;
function DoIt(const Values: TIntegerArray): ReturnType;
然后函数将 Dynamic Array 作为输入。你可以assign/pass一个Variant
持有一个数组到一个动态数组variable/parameter。编译器足够聪明,可以调用 RTL 的 VarToDynArray()
函数来分配一个新的动态数组,该数组具有 Variant
的数组元素的副本。如果不复制数组数据,就无法将包含数组的 Variant
传递给动态数组。
然而,如果函数在其参数列表中直接采用 array of Integer
,例如:
function DoIt(const Values: array of Integer): ReturnType;
然后它需要一个 Open Array 作为输入:
an Delphi function that has an open array parameter can be called by explicitly passing two parameters:
- A pointer to the first element of the array
- A count, which is the value of the last index (that is, the size/number of array elements, minus one)"
您不能将 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
的数组直接传递给函数,根本不会复制数组元素。