我有一些函数可以接受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;
这是安全的做法,还是可能引起我没有考虑的问题?
最佳答案
只要阵列兼容,该技术本身不会造成伤害。 array of TObject
的成员只是对对象的引用。由于可以从祖先引用中安全地使用对象,因此不存在固有问题。
当然,您在问题中显示的代码是安全的。如果就所有权模式而言,您甚至可以Free
删除/删除的对象实例。
也就是说,存在编译器无法执行其任何典型类型安全检查的风险。
在极端情况下,您可以在array of Byte
和array of TObject
之间进行转换
更巧妙地,您可能会意外地在不兼容的对象类型的数组之间进行转换(例如,在array of TButton
和array of TQuery
之间进行转换)。使用单个对象时,可以选择使用(<object> as <type>)
进行选中的类型转换。这将执行编译时检查,以验证类型是否在同一层次结构中(否则,强制转换是不兼容的),并执行运行时检查以确保对象实例实际上是正确的类型。
尽管删除和交换数组中的对象是安全的,但var
引用意味着您还可以将对象添加到数组中。现在,array of TButton
会强制您添加TButton
(或子类)实例;将类型转换为array of TObject
意味着您可以不小心将任何其他对象添加到数组。当函数返回时,代码将尝试非常错误地使用对象。您几乎肯定会遇到奇怪的行为和/或访问冲突。由于根问题已在程序的较早版本中无声引入,因此调试起来将更加困难。
结论
尽管该技术有效,但最好还是建议您使用TObjectList
。
这保留了基于标准对象的类型检查。
它支持与数组相似的用法,因此通常是一个很好的替代品。
此外,该容器还可以在添加和删除项目时动态调整大小,而无需手动调整大小。
唯一的不便之处是您必须创建和销毁TObjectList
。
尽管您必须在TList
和类类型之间执行未经检查的强制转换,甚至Pointer
还是通常更好的选择。
关于arrays - 在将动态数组作为变量参数传递之前是否可以强制转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49382574/