将一个通用的 TArray 转换为一个 varArray。

问题描述 投票:2回答:1

我想把一个 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;

但在每一行都产生了以下的编译错误,我在每一行都分配了一个... TVariant:

[dcc32 Error] Unit1.pas(36).E2010 不兼容类型:"Variant "和 "T"。E2010 不兼容类型:"Variant "和 "T

delphi generics delphi-xe7 variant
1个回答
3
投票

问题的标题说你想处理通用的 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,然而我发现那个也是次优的。

© www.soinside.com 2019 - 2024. All rights reserved.