将泛型 TArray 转换为 varArray



我正在尝试将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;

但它在我为Variant分配T的每一行都会产生以下编译错误:

[dcc32 错误] 单元 1.pas(36(: E2010 不兼容的类型:"变体"和 "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开发人员感到困惑。

德尔福 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.

开放数组解决了这个问题,但您需要将其"转换"为动态数组才能与 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中编写更好的实现,但是我发现那个也是次优的。

相关内容

  • 没有找到相关文章

最新更新