在将动态数组作为变量参数传递之前投射动态数组是否安全?

时间:2018-03-20 11:05:37

标签: 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(AIndex);
  end;
  SetLength(AArray, Length(AArray) - 1);
end;

为了重用相同的函数,我将TObject的后代类转换为TObjectArray,然后将它们传递给我的函数,例如:

var
  Buttons : array of TButton;
begin
  SetLength(Buttons, 1);
  Buttons[0] := Button1;

  //...

  DeleteAt(TObjectArray(Buttons), 0);
end;

这是一种安全的做法,还是会引起一些我没有考虑过的问题?

1 个答案:

答案 0 :(得分:3)

如果阵列兼容,该技术本身不会造成伤害。 array of TObject的成员只是对象的引用。由于可以从祖先引用中安全地使用对象,因此没有固有的问题。

当然,您在问题中显示的代码是安全的。如果在您的所有权模式方面有意义,您甚至可以Free删除/删除的对象实例。

也就是说,存在编译器无法执行任何典型类型安全检查的风险。

  • 在极端情况下,您可以在例如array of Bytearray of TObject
  • 之间进行投射
  • 更巧妙的是,您可能会意外地在不兼容的对象类型的数组之间进行投射(例如,在array of TButtonarray of TQuery之间投射)。使用单个对象时,您可以选择使用(<object> as <type>)进行检查类型转换。这将执行编译时检查以验证类型是否在同一层次结构中(否则保证转换不兼容),并执行运行时检查以确保对象实例实际上具有正确的类型。
  • 虽然删除和交换数组中的对象是安全的,但 var 引用意味着您还可以将对象添加到数组中。现在,array of TButton强制您添加TButton(或子类)实例;将类型转换为array of TObject意味着您可能会意外地将任何其他对象添加到数组中。当函数返回时,代码将尝试非常错误地使用对象。您几乎肯定会遇到奇怪的行为和/或访问违规行为。由于 root问题已在程序早期默默引入,因此调试起来会更加困难。

结论

虽然该技术有效,但建议您使用TObjectList

  • 这保留了基于标准对象的类型检查。
  • 它支持对数组的类似用法,因此通常是一个很好的替代品。
  • 作为额外奖励,容器可以在添加和删除项目时动态调整大小 - 无需再手动调整大小。
  • 唯一的小麻烦是您必须创建并销毁TObjectList

即使TList通常是更好的选择,但您必须在Pointer和类类型之间执行未经检查的投射。