将通用TArray转换为varArray

我正在尝试将array of T转换为VariantvarArray)。

对于非通用类型(即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),VarType(Result)
  );

  for i := Low(AValues) to High(AValues) do 
    Result[i] := AValues[i];
end;

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

[dcc32错误] Unit1.pas(36):E2010不兼容的类型:'Variant'和 'T'

iCMS 回答:将通用TArray转换为varArray

问题的标题表明您要处理通用的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;

当第一个不变式接受真实的动态数组作为参数时,后者则采用open array。对于Delphi开发人员来说,这种不幸的语言设计是常规的source of confusion

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,2]); // open array constructor
end.

上面的OpenArrayToVarArray<T>例程在性能和内存使用方面都非常无效,因为它从开放数组到动态数组一个一个地复制元素。如果您确实需要支持开放式数组,则您可能应该编写受RTL DynArrayToVariant启发的更好的实现,但是我发现它也不是最优的。

本文链接:https://www.f2er.com/2296833.html

大家都在问