Почему приведение параметра открытого массива к типу массива вызывает недопустимый тип e2089?

я использую Delphi 2007 (Pre generics) и я определил много функций, которые могут использоваться для всех массивов TObjectпотомки, пример:

function IndexOf(AArray : array of TObject; AItem : TObject) : integer;
begin
  //...
end;

для передачи им динамических массивов потомков TObject я определил тип массива TObjectArray = array of TObject. Таким образом, я могу бросить динамические массивы и передать их своим функциям без каких-либо проблем:

type
  TChild = class(TObject);

...

procedure Test();
var
  Items : array of TChild;
  Item : TChild;
begin
  //...
  IndexOf(TObjectArray(Items), Item);
end;

проблема возникает, когда я пытаюсь передать им параметры открытого массива:

procedure  Test(AItems : array of TChild);
var
  Item : TChild;
begin
  //...
  IndexOf(TObjectArray(AItems), Item);
end;

In в этих случаях компилятор выдает следующее сообщение об ошибке:

E2089 неверный typecast

почему это происходит и как я могу избежать этого?

1 ответов


вам не нужно typecast при передаче любого типа массива в параметр открытого массива, при условии, что элементы одного типа. Вы можете передать массив как есть, открытый массив примет его просто отлично. В этом весь смысл открытых массивов.

type
  TChild = class(TObject);

...

function IndexOf(AArray : array of TObject; AItem : TObject) : integer;
begin
  //...
end;

procedure Test();
var
  Items : array of TObject;
  Item : TChild;
begin
  //...
  IndexOf(Items, Item);
end;

procedure Test2();
var
  Items : array[0..N] of TObject;
  Item : TChild;
begin
  //...
  IndexOf(Items, Item);
end;

procedure Test3(AItems : array of TObject);
var
  Item : TChild;
begin
  //...
  IndexOf(AItems, Item);
end;

однако вы не можете передать массив TChild где массив это. Компилятор отклонит его с ошибкой "несовместимые типы". Входной массив должен использовать тот же тип элемента, как открыть матрица.

простой typecast может исправить это при передаче динамического массива или фиксированного массива:

procedure Test();
type
  TObjectArray = array of TObject;
var
  Items : array of TChild;
  Item : TChild;
begin
  //...
  IndexOf(TObjectArray(Items), Item);
end;

procedure Test2();
type
  TObjectFixedArray = array[0..N] of TObject;
  PObjectFixedArray = ^TObjectFixedArray;
var
  Items : array[0..N] of TChild;
  Item : TChild;
begin
  //...
  IndexOf(PObjectFixedArray(@Items)^, Item);
end;

но вы просто не можете типизировать открытый массив для любого другого типа массива. Различные типы массивов имеют разные макеты памяти (типизация динамического массива в другой динамический массив или фиксированный массив в другой фиксированный массив не изменяет макет памяти типизируемого массива).

в случае открытого массива, это даже не массив вообще, это просто указатель на первый элемент в массив, и есть второй скрытый параметр для длины массива. Другими словами, такого рода заявление:

procedure Test3(AItems : array of TChild);

фактически реализуется компилятором за кулисами, как это:

procedure Test3(AItems : ^TChild; AItems_High: Integer);

Итак, вам нужно будет сделать копию открытых элементов массива в другой массив, а затем передать этот массив:

procedure Test3(AItems : array of TChild);
var
  Items: array of TObject;
  Item : TChild;
  I: Integer;
begin
  //...
  SetLength(Items, Length(AItems));
  For I := Low(AItems) to High(AItems) do
    Items[I] := AItems[I];
  IndexOf(Items, Item);
end;