我想把一个 array of T
变成 Variant
(varArray
).
对于非通用类型(即: Integer
),我使用了以下函数。
function ToVarArray(AValues : array of Integer) : Variant;
var
i : integer;
begin
Result := VarArrayCreate(
[Low(AValues), High(AValues)],
varInteger
);
for i := Low(AValues) to High(AValues) do
Result[i] := AValues[i];
end;
我在尝试用通用类型做同样的事情时遇到了一些问题。TArray
:
uses
System.Generics.Collections;
type
TArray = class(System.Generics.Collections.TArray)
public
class function ToVarArray<T>(const AValues: array of T) : Variant; static;
end;
我尝试了以下的方法。
class function TArray.ToVarArray<T>(const AValues: array of T) : Variant;
var
i : integer;
Tmp : T;
begin
Result := Tmp;
Result := VarArrayCreate(
[Low(AValues), High(AValues)],
VarType(Result)
);
for i := Low(AValues) to High(AValues) do
Result[i] := AValues[i];
end;
但在每一行都产生了以下的编译错误,我在每一行都分配了一个... T
到 Variant
:
[dcc32 Error] Unit1.pas(36).E2010 不兼容类型:"Variant "和 "T"。E2010 不兼容类型:"Variant "和 "T
问题的标题说你想处理通用的 TArray<T>
但第一句话就说这是 array of T
. 你可能认为这两个术语指的是相同的数据结构(动态数组),而且大多数情况下是这样的,但是如果你用它们来代替一个过程函数的参数声明,它们就会有所不同。
因此,下面的方法具有不同的签名,接受不同类型的参数。
class function TArray.ToVarArray<T>(const AValues: TArray<T>): Variant;
class function TArray.ToVarArray<T>(const AValues: array of T): Variant;
第一个不变式接受真正的动态数组作为参数, 而后者接受一个动态数组作为参数 开放式阵列. 这种不幸的语言设计是正规的 祸根 为Delphi开发者提供。
Delphi RTL已经包含了将动态数组转换为适当类型的变异数组的函数----------。DynArrayToVariant
. 它以动态数组的初始元素指针和数组的类型信息作为参数。要使用属性,你可以写这样的代码。
uses
System.Variants;
class function TArray.DynArrayToVarArray<T>(const AValues: TArray<T>): Variant;
begin
DynArrayToVariant(Result, @AValues[0], TypeInfo(TArray<T>));
end;
如果你试图在静态数组中使用这个例程,你的代码将无法编译。
var
SA: array[0..2] of Integer;
begin
SA[0] := 0;
SA[1] := 1;
SA[2] := 2;
{ E2010 Incompatible types: 'System.TArray<System.Integer>' and 'array[0..2] of Integer' }
TArray.DynArrayToVarArray<Integer>(SA);
end.
Open数组解决了这个问题,但是你需要将它 "转换 "为动态数组,以便与RTL的 DynArrayToVariant
.
class function TArray.OpenArrayToVarArray<T>(const AValues: array of T): Variant;
var
LArray: TArray<T>;
Index: Integer;
begin
SetLength(LArray, Length(AValues));
for Index := Low(AValues) to High(AValues) do
LArray[Index] := AValues[index];
Result := DynArrayToVarArray<T>(LArray);
end;
var
DA: TArray<Integer>;
SA: array[0..2] of Integer;
begin
DA := [0, 1, 2];
SA[0] := 0;
SA[1] := 1;
SA[2] := 2;
{ these all work }
TArray.OpenArrayToVarArray<Integer>(DA); // dynamic array
TArray.OpenArrayToVarArray<Integer>(SA); // static array
TArray.OpenArrayToVarArray<Integer>([0, 1, 2]); // open array constructor
end.
以上 OpenArrayToVarArray<T>
例程在性能和内存使用方面都是非常无效的,因为它将一个个元素从开放数组复制到动态数组。如果你真的需要支持开放数组,你可能应该写更好的实现,灵感来自于RTL的 DynArrayToVariant
,然而我发现那个也是次优的。