Ian Branch 128 Posted June 25, 2021 Hi Team, I am playing in an area I have no experience in, again. I have the following routine found while googling..... D10.4.2. function RecordToArray(aDataSet: TDataSet); var Data: array of variant; aRecord: array of TVarRec; i: integer; max: integer; begin max := aDataSet.fields.count - 1; // set the lenghth of the arecord array to be the same as the number of // elements in the data array SetLength(arecord, max + 1); SetLength(data, max + 1); // set the variant type pointers to the data array for i := 0 to max do begin arecord[i].VType := vtVariant; arecord[i].VVariant := @data[i]; end; Result := aRecord; end; The objective is to copy the contents of a table row into an array, which is then returned to the calling routine so the table can be closed and the array values accessed throughout the remainder of the program. I want to keep the routine generic so I can use where ever it is convenient. The contents of the fields can be any valid data type. The array can vary in length. The original routine simply took the array and copied it back into the dataset and didn't return anything. I figured, obviously incorrectly, that if 'arecord' is declared as a TVarRec, then the function return should be an Array. Delphi didn't like it. OK. I declared a type of TVarArray = array of variant;, and set the return as TVarArray. Nope, Delphi says I must return a dynamic array. How do I do that please? What should the return type be? Regards & TIA, Ian Share this post Link to post
Mark- 29 Posted June 25, 2021 Couple of ways to accomplish it, One simple method. type TVariantArray = array of variant; function Foo(data:byte):TVariantArray; begin SetLength(result,2); result[0]:=data + 123; result[1]:='ABCD'; end; procedure FooTest; var res:TVariantArray; begin res:=Foo(1); ShowMessage(IntToStr(res[0]) + ' ' + res[1]); end; Share this post Link to post
Lars Fosdal 1793 Posted June 25, 2021 You could also do something like this, which gives you the results converted to actual types instead of variants. Share this post Link to post
0x8000FFFF 22 Posted June 25, 2021 There is one fundamental thing missing in your function - copying the field values. The other thing is that you don't need to mess with TVarRec at all. Here's how I would do it: function RecordToArray(DS: TDataSet): TArray<Variant>; var FieldIndex: Integer; begin SetLength(Result, DS.FieldCount); for FieldIndex := 0 to DS.FieldCount - 1 do Result[FieldIndex] := DS.Fields[FieldIndex].Value; end; procedure ArrayToRecord(DS: TDataSet; const Values: TArray<Variant>); var FieldIndex: Integer; begin Assert(DS.FieldCount = Length(Values)); for FieldIndex := 0 to DS.FieldCount - 1 do DS.Fields[FieldIndex].Value := Values[FieldIndex]; end; Another option is to use variant array: function RecordToVarArray(DS: TDataSet): Variant; var FieldIndex: Integer; Data: PVariant; begin Result := VarArrayCreate([0, DS.FieldCount - 1], varVariant); Data := VarArrayLock(Result); try for FieldIndex := 0 to DS.FieldCount - 1 do begin Data^ := DS.Fields[FieldIndex].Value; Inc(Data); // move to next elemnt in resulting array end; finally VarArrayUnlock(Result); end; end; procedure VarArrayToRecord(DS: TDataSet; const Values: Variant); var FieldIndex: Integer; Data: PVariant; begin Assert(VarIsType(Values, varArray or varVariant)); Assert(VarArrayDimCount(Values) = 1); Data := VarArrayLock(Values); try for FieldIndex := 0 to DS.FieldCount - 1 do begin DS.Fields[FieldIndex].Value := Data^; Inc(Data); // move to next elemnt in resulting array end; finally VarArrayUnlock(Values); end; end; // you could then access those value using index: var Values := RecordToVarArray(DS); Writeln(VarToStr(Values[0])); Writeln(VarToStr(Values[1])); ... 1 Share this post Link to post
Ian Branch 128 Posted June 25, 2021 All, Thank you for your inputs & suggestions. I have gone with 0x8000FFFF's first suggestion for its simplicity and flexibility. Again, my thanks to all. Regards, Ian Share this post Link to post