Why am I getting an error about incompatible types of Delphi (array and dynamic array)?

( EDIT : This follows from Whether object reference is taken into account in Windows-based Delphi applications, and if so, what is its purpose? And Dynamic arrays and memory management in Delphi ).

I have two classes ( TGenericHoldingSummary , TGenericHoldingResultSet ) and one record ( TGenericHoldingResult ).

  • TGenericHoldingSummary contains a single TGenericHoldingResultSet , which is set to nil and lazy-loaded from the database, if and when required.
  • TGenericHoldingResultSet contains a dynamic array of TGenericHoldingResult records.

In the example below, an error occurs when you assign it to the TGenericHoldingResultSet constructor.

 TGenericHoldingResult = record code : Integer; level : String; msg : String; end; TGenericHoldingResultSet = class(TObject) public // Lifecycle constructor Create(parent : TGenericHoldingSummary; resArr : Array of TGenericHoldingResult); destructor Destroy; // Accessors function ResultCount() : Integer; function Result(i : Integer) : TGenericHoldingResult; private // Variables summary : TGenericHoldingSummary; resultArray : Array of TGenericHoldingResult; end; TGenericHoldingSummary = class(TObject) public // Note that the summary object 'owns' the results, and deallocates // its memory in the destructor. function getResultSet: TGenericHoldingResultSet; private // Member variables resultSet: TGenericHoldingResultSet; end; // Note that the summary object 'owns' the results, and deallocates // its memory in the destructor. function TGenericHoldingSummary.getResultSet() : TGenericHoldingResultSet; var sql : String; i : Integer; resultArray : Array of TGenericHoldingResult; begin if resultSet = nil then begin // Get results via SQL. SetLength(resultArray, holding.clientDataSet.RecordCount); for i := 0 to holding.clientDataSet.RecordCount - 1 do begin resultArray[i].code := holding.clientDataSet.FieldByName('code').AsInteger; resultArray[i].level := holding.clientDataSet.FieldByName('level').AsString; resultArray[i].msg := holding.clientDataSet.FieldByName('message').AsString; end; resultSet := TGenericHoldingResultSet.Create(self, resultArray); end; result := resultSet; end; // Lifecycle constructor TGenericHoldingResultSet.Create(parent : TGenericHoldingSummary; resArr : Array of TGenericHoldingResult); begin summary := parent; // The following *should* work, shouldn't it? // Eg, seeing as dynamic arrays a reference counted in Delphi for // all platforms, this should simply increment the reference count. resultArray := resArr; end; 

The error is below:

 [DCC Error] GenericHolding.pas(302): E2010 Incompatible types: 'Dynamic array' and 'Array' 
+4
source share
1 answer

You cannot assign an open array to a dynamic array. See Open Array Parameters .

Note. The syntax for open array parameters is similar to the syntax for dynamic array types, but they do not mean the same thing. The previous example creates a function that accepts any array of Char elements, including (but not limited to) dynamic arrays. To declare parameters that should be dynamic arrays, you need to specify an identifier of the type:

 type TDynamicCharArray = array of Char; function Find(const A: TDynamicCharArray): Integer; 

A good summary of using open arrays and the difference with a dynamic array can be found here: Open Array Parameters .


If you have a version of Delphi that supports generics, you can declare the constructor header:

 constructor TGenericHoldingResultSet.Create(parent : TGenericHoldingSummary; const resArr : TArray<TGenericHoldingResult>); 

and your resultArray as TArray<TGenericHoldingResult> .

This avoids declaring a specific type for the array.

As David noted, open arrays have an advantage because they have a wider precedent and should be used when possible.

+5
source

Source: https://habr.com/ru/post/972438/


All Articles