Почему приведение параметра открытого массива к типу массива приводит к ошибочному типу E2089? - PullRequest
0 голосов
/ 18 мая 2018

Я использую Delphi 2007 (предварительные шаблоны), и я определил много функций, которые можно использовать для всех массивов потомков 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 Неверный тип ввода

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

1 Ответ

0 голосов
/ 18 мая 2018

Вам не нужно указывать тип при передаче ЛЮБОГО типа массива в параметр открытого массива, если элементы одного типа.Вы можете передать массив как есть, открытый массив примет его просто отлично.В этом весь смысл открытых массивов.

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, где ожидается массив TObject.Компилятор отклонит его с ошибкой «несовместимые типы».Входной массив должен использовать тот же тип элемента, что и открытый массив.

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

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;

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

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

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;
...