为什么将开放数组参数转换为数组类型会导致 E2089 Invalid typecast?
Why casting an open array parameter to an array type causes E2089 Invalid typecast?
我正在使用 Delphi 2007(Pre generics)并且我定义了许多可用于 TObject
的所有数组的函数s 后代,例如:
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;
在这些情况下,编译器会引发以下错误消息:
E2089 Invalid 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;
但是,您不能在需要 TObject
数组的地方传递 TChild
数组。编译器将拒绝它并返回 "incompatible types" 错误。输入数组必须使用与开放数组相同的元素类型。
传递动态数组或固定数组时,一个简单的类型转换可以解决这个问题:
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;
我正在使用 Delphi 2007(Pre generics)并且我定义了许多可用于 TObject
的所有数组的函数s 后代,例如:
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;
在这些情况下,编译器会引发以下错误消息:
E2089 Invalid 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;
但是,您不能在需要 TObject
数组的地方传递 TChild
数组。编译器将拒绝它并返回 "incompatible types" 错误。输入数组必须使用与开放数组相同的元素类型。
传递动态数组或固定数组时,一个简单的类型转换可以解决这个问题:
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;