Arrays 在将动态数组作为变量参数传递之前强制转换它是否安全?
我有一些函数可以接受Arrays 在将动态数组作为变量参数传递之前强制转换它是否安全?,arrays,delphi,casting,dynamic-arrays,delphi-2007,Arrays,Delphi,Casting,Dynamic Arrays,Delphi 2007,我有一些函数可以接受TObject数组作为var参数,例如: type TObjectArray = array of TObject; ... procedure DeleteAt(var AArray : TObjectArray; AIndex : integer); begin while(AIndex < Length(AArray) - 1) do begin AArray[AIndex] := AArray[AIndex + 1]; Inc(A
TObject
数组作为var
参数,例如:
type
TObjectArray = array of TObject;
...
procedure DeleteAt(var AArray : TObjectArray; AIndex : integer);
begin
while(AIndex < Length(AArray) - 1) do
begin
AArray[AIndex] := AArray[AIndex + 1];
Inc(AIndex);
end;
SetLength(AArray, Length(AArray) - 1);
end;
var
Buttons : array of TButton;
begin
SetLength(Buttons, 1);
Buttons[0] := Button1;
//...
DeleteAt(TObjectArray(Buttons), 0);
end;
这是一种安全的做法,还是可能会导致一些我没有考虑的问题?如果阵列兼容,该技术本身不会造成危害。TObject的
数组的成员只是对对象的引用。由于可以从祖先引用安全地使用对象,因此不存在固有的问题
当然,您在问题中显示的代码是安全的。您甚至可以释放要删除/删除的对象实例,如果这对您的所有权模式有意义的话
也就是说,编译器无法执行任何典型的类型安全检查是有风险的
- 在极端情况下,您可以在例如
字节数组
和TObject数组
- 更微妙的是,您可能会意外地在不兼容对象类型的数组之间强制转换(例如,在TButton的
数组
和TQuery的数组
之间强制转换)。使用单个对象时,您可以选择使用(as)
进行选中类型转换。这将执行编译时检查以验证类型是否在同一层次结构中(否则将保证强制转换不兼容),并执行运行时检查以确保对象实例实际上是正确的类型
- 虽然移除和交换数组中的对象是安全的,但是
var
参考意味着您也可以将对象添加到数组中。现在,TButton的数组
强制您添加TButton
(或子类)实例;将typecast转换为TObject的数组
意味着您可以意外地将任何其他对象添加到数组中。当函数返回时,代码将尝试错误地使用对象。你几乎肯定会有奇怪的行为和/或访问违规。由于在程序的前面已经悄悄地引入了根问题,因此调试它们将更加困难
结论
虽然该技术可行,但最好使用TObjectList
- 这将保留标准的基于对象的类型检查
- 它支持与数组类似的用法,因此通常是一个很好的替代品
- 作为一个额外的好处,容器可以在您添加和删除项目时动态调整大小-无需再手动调整大小
- 唯一的小麻烦是您必须创建并销毁
TObjectList
即使是TList
通常也是一个更好的选择,尽管您必须在Pointer
和类类型之间执行未经检查的强制转换。如果您只强制转换与对象兼容的数组,那么它可能会起作用。但无论如何,这是可怕的。为什么不使用泛型TList?@AndreiGalatyn:因为我使用的是Delphi 2007,所以你可以使用常规类TList/TObjectList。当然你可以做得更好。但是,是的,这会有结果的。@DavidHeffernan:你能解释一下你的意思吗?谢谢你的解释。在大多数情况下,我仍然更喜欢数组,因为否则每次使用它们时,我都应该创建并释放列表和强制转换项。无论如何,你的回答已经完全澄清了我所有的疑问!