Reputation: 27266
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...
Upvotes: 11
Views: 4902
Reputation: 6848
Assuming that in the end you want to get the output of the array as a string (with the procedure GetSomething). I think you can easily do this using Variants
.
Define your array like this:
MyArray = array of variant;
The GetSomething procedure
now is simple:
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;
And the result is the expected.
This line:
Variable:= GetSomething(['some string', 123, 'something else', 12.3, false]);
Return this result:
some string | 123 | something else | 12,3 | False |
Upvotes: 0
Reputation: 25
It's really easy and it's not different between Delphi's versions
first you need to a record of name and type such as this :
Customer = record
OINTCUSTID : INTEGER ;
CUSTTYPE : SmallInt;
NAME : string[30];
end;
and now different your array like this :
Glb_CUSTOMER :ARRAY [1..20] OF Customer;
Now you have an array with different type.
Upvotes: 0
Reputation: 3820
Since is for use as an parameter, you could use the array of const
construct.
Also known as variant open array parameters. More on my answer on this other question.
It works like your desired array of different types. Delphi docwiki documentation on that theme
Upvotes: 0
Reputation: 11217
Oddly enough, nobody has yet mentioned variant records, which have been a feature of Pascal for decades:
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;
Upvotes: 3
Reputation: 612784
Arrays are homogeneous. As the documentation says:
An array represents an indexed collection of elements of the same type (called the base type).
Therefore you can achieve your goal only by way of a base type that can hold differing types of data. Such a data type is known as a variant data type.
In Delphi there are a number of possibilities for variant data types. There is the venerable COM Variant
type. There is the new kid on the block, TValue
, which was added to support new style RTTI. And there are many third party options. Typically these third party options exist to support persistence frameworks.
Upvotes: 1
Reputation: 136381
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.
Upvotes: 13