arraysdelphidelphi-xe2

Can I define an array type of different type values?


I'd like to define an array type which consists of different type values, such as String, Integer, Boolean, Double, etc. but no objects, structures, or anything of that nature. Then I'd like to use this type as a function argument, for example...

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;

and use it like...

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

Then, how do I identify what type each element is when iterating through such an array?

I'm pretty sure this is possible, but have no idea even what terminology to search for. How do I do this?

Would I have to define this as an array of Variants? Or is there a way to define exactly which types the array accepts?

EDIT

Not to change the question any, but after the answer by RRUZ, I found an intriguing article about the performance when doing this exact thing different ways...


Solution

  • If your Delphi version supports RTTI, you can use an array of TValue and the Kind property like so.

    {$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.
    

    Another option is use an 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.