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:你能解释一下你的意思吗?谢谢你的解释。在大多数情况下,我仍然更喜欢数组,因为否则每次使用它们时,我都应该创建并释放列表和强制转换项。无论如何,你的回答已经完全澄清了我所有的疑问!