delphi 我可以定义不同类型的数组类型吗?

6pp0gazn  于 2022-11-29  发布在  其他
关注(0)|答案(6)|浏览(219)

我想定义一个数组类型,它由不同的类型组成,比如StringIntegerBooleanDouble等,但是没有对象,结构,或者任何类似的东西。然后我想用这个类型作为函数参数,比如...

type
  TMyArray = array of ...?...;

function GetSomething(const Input: TMyArray): String;
var
  X: Integer;
begin
  for X:= 0 to Length(Input) - 1 do begin
    //Identify type and handle accordingly...
    //Serialize data for the result...

  end;
end;

用它来...

Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);

那么,在遍历这样的数组时,如何识别每个元素的类型呢?
我很确定这是可能的,但是我甚至不知道要搜索什么术语。我该怎么做?
我必须把它定义为一个变量数组吗?或者有没有一种方法可以精确地定义数组接受哪些类型?

编辑

不是要改变任何问题,但由RRUZ的答案后,我发现an intriguing article的性能时,做这件事不同的方式...

6ie5vjzr

6ie5vjzr1#

如果您的 Delphi 版本支持RTTI,则可以使用TValue数组和Kind属性,如下所示。

{$APPTYPE CONSOLE}

uses
  System.TypInfo,
  System.Rtti,
  System.SysUtils;

function GetSomething(const Input: array of TValue): String;
var
  X: Integer;
  LValue : TValue;
begin
  for LValue in Input  do begin
     case LValue.Kind of
       tkUnknown: Writeln('Unknown');
       tkInteger:  Writeln(Format('The Kind of the element is Integer and the value is %d',[LValue.AsInteger]));
       tkChar: Writeln('Char');
       tkEnumeration: if LValue.TypeInfo=TypeInfo(Boolean) then Writeln(Format('The Kind of the element is Boolean and the value is %s',[BoolToStr(LValue.AsBoolean, True)]));
       tkFloat: Writeln(Format('The Kind of the element is Float and the value is %n',[LValue.AsExtended]));
       tkString: Writeln('String');
       tkSet: Writeln('Set');
       tkClass: Writeln('Class');
       tkMethod:Writeln('method');
       tkWChar: Writeln('WChar');
       tkLString: Writeln('String');
       tkWString: Writeln('String');
       tkVariant: Writeln('Variant');
       tkArray: Writeln('Array');
       tkRecord: Writeln('Record');
       tkInterface: Writeln('Interface');
       tkInt64: Writeln('Int64');
       tkDynArray: Writeln('DynArray');
       tkUString:  Writeln(Format('The Kind of the element is String and the value is %s',[LValue.AsString]));
       tkClassRef:  Writeln('Class Ref');
       tkPointer: Writeln('Pointer');
       tkProcedure:  Writeln('procedure');
     end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.

另一个选项是使用array of const

{$APPTYPE CONSOLE}

uses
  SysUtils;

procedure GetSomething(const Input: array of const);
var
  LIndex: Integer;
begin
  for LIndex := Low(Input) to High(Input) do
  begin
    case Input[LIndex].VType of
      vtWideString: Writeln('WideString = ''', WideString(Input[LIndex].VWideChar), '''');
      vtInt64: Writeln('Int64 = ', Input[LIndex].VInt64^);
      vtCurrency: Writeln('Currency = ', CurrToStr(Input[LIndex].VCurrency^));
      vtInteger: Writeln('Integer = ', Input[LIndex].VInteger);
      vtBoolean: Writeln('Boolean = ', BoolToStr(Input[LIndex].VBoolean, True));
      vtChar: Writeln('Char = ''', Input[LIndex].VChar, '''');
      vtExtended: Writeln('Extended = ', FloatToStr(Input[LIndex].VExtended^));
      vtString: Writeln('ShortString = ''', Input[LIndex].VString^, '''');
      vtPChar: Writeln('PChar = ''', Input[LIndex].VPChar, '''');
      vtAnsiString: Writeln('AnsiString = ''', Ansistring(Input[LIndex].VAnsiString), '''');
      vtWideChar: Writeln('WideChar = ''', Input[LIndex].VWideChar, '''');
      vtPWideChar: Writeln('PWideChar = ''', Input[LIndex].VPWideChar, '''');
      vtUnicodeString : Writeln('UnicodeString = ''', string(Input[LIndex].VUnicodeString), '''');
    else
      Writeln('Unsupported');
    end;
  end;
end;

begin
  try
    GetSomething(['some string', 123, 'something else', 12.3, false]);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
  Readln;
end.
odopli94

odopli942#

奇怪的是,至今还没有人提到变体记录,这是Pascal几十年来的一个特点:

type
  TVarRecType = (vrtInteger, vrtDouble {other types go here});
  TVarRec = record
    Field1: string; { can be omitted }
  case RecType: TVarRecType of
    vrtInteger:
      IntValue: integer;
    vrtDouble:
      DblValue: double;
    { other cases go here }
  end;

var
  VarRec: TVarRecType;
begin
  VarRec.Field1 := 'This is an example.';
  VarRec.RecType := vrtInteger;
  VarRec.IntValue := 4711;
  {...}
  VarRec.RecType := wrtDouble;
  VarRec.DblValue := Pi;
  {...}
end;

{ Oops, forgot the array part }
type
  TVarRecArr = array[1..15] of TVarRec;
var
  VarRecArr: TVarRecArr;
begin
  VarRecArr[1].Field1 := 'This is the first record';
  VarRecArr[1].RecType := wrtInteger;
  VarRecArr[1].IntValue := 1;
  {...}
end;
pkmbmrz7

pkmbmrz73#

阵列是同构的。如文档所述:
数组表示同一类型(称为基类型)的元素的索引集合。
因此,您只能通过一个可以保存不同类型数据的基类型来实现您的目标。这种数据类型称为variant data type
在 Delphi 中,有很多可能的变体数据类型。有古老的COM Variant类型。有块上的新kid,TValue,它是为了支持新风格的RTTI而添加的。还有很多第三方选项。通常这些第三方选项的存在是为了支持持久性框架。

pu82cl6c

pu82cl6c4#

由于是作为参数使用的,因此可以使用array of const构造。也称为 variant open array parameters. More on my answer on this other question
它的工作原理就像你想要的不同类型的数组一样。

5rgfhyps

5rgfhyps5#

这真的很简单,而且 Delphi 的版本之间没有什么不同
首先,您需要一个名称和类型的记录,如下所示:

Customer = record
OINTCUSTID      : INTEGER ;
CUSTTYPE        : SmallInt;
NAME            : string[30];
end;

现在数组的不同之处如下所示:

Glb_CUSTOMER       :ARRAY [1..20] OF Customer;

现在你有一个不同类型的数组。

mgdq6dx1

mgdq6dx16#

假设最后你想把数组的输出作为一个字符串(用过程GetSomething),我想你可以用Variants很容易地做到这一点。
定义数组,如下所示:

MyArray = array of variant;

现在的GetSomethingprocedure非常简单:

function TForm3.GetSomething(const Input: TMyArray): String;
var
  X: Integer;
begin
  for X:= 0 to Length(Input) - 1 do
    //Identify type and handle accordingly...
    //Serialize data for the result...
    Result := Result + VarToStrDef(Input[X], '?') + ' | ';
end;

而结果也是意料之中的。
这一行:

Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);

返回此结果:
一些字符串|一百二十三|别东西|12.3秒|错误|

相关问题