TList
中的{p> TOjectList
和Generics.Collections
具有.List
属性,这是一个枚举器。
例如:
oList := TObjectList<TItem>.Create;
// Add items to oList
for Item in oList.List do begin
// Do something with Item
end;
这很整洁,但结果却很严重。 .List
只需阅读FList
(TList
和TObjectList
上的私人声明),这只是arrayofT
。
由于动态数组的大小加倍,只要项目的大小超出其大小,就意味着它有空间用于未使用的项目。
如果您添加了3个TItem
,则实际的FList
长度为4个项目,第四个(和最后一个)项目为nil
。
因此,使用TObjectList
的{{1}}是不安全的,因为如果您的.List
没有TObjectList
值,那么它可能会导致访问冲突2(例如1,2,4,8,16等)。
以下代码可能会导致访问冲突:
.Count
当然,安全解决方案是使用for Item in oList.List do begin
Writeln(Item.ClassName);
end;
:
.Count
这不像那样和枚举器一样。 (当然,您也可以检查for I := 0 to oList.Count - 1 do begin
Item := oList.Items[I];
Writeln(Item.ClassName);
end;
是否为Item
。)
我的问题是:
nil
不是实际的枚举符?.List
/ TList
有实际的枚举符吗?以下是TObjectList
的示例(其中TForm
只添加一行,btn1
为mmo1
)。
TMemo
现在,使用procedure TForm2.btn1Click(Sender: TObject);
var
Line: string;
begin
Line := 'Line';
mmo1.Lines.Add(Line);
fList.Add(Line);
mmo1.Lines.Add(Format('Count: %d; Actual length: %d', [fList.Count, Length(fList.List)]));
for Line in fList.List do begin
mmo1.Lines.Add(Format('Found: "%s"', [Line]));
end;
end;
不会引发访问冲突。但是当我点击3次后,我得到以下内容:
string
答案 0 :(得分:16)
TList<T>
中的{p>TOjectList<T>
和Generics.Collections
具有List
属性,这是一个枚举器。
不,不是这样。 List
属性是动态数组。动态数组内置了对枚举的支持。
由于动态数组的大小加倍,只要项目的大小超出其大小,就意味着它有空间用于未使用的项目。
这也不是真的。动态数组不会自动调整大小。必须通过调用SetLength
显式调整它们的大小。 TList<T>
类使用对SetLength
的调用来管理存储列表内容的基础动态数组的容量。
为什么
List
不是实际的枚举器?
如果我记得,最近在XE3中添加了List
属性。其目的是允许直接访问基础列表,这是其他方式无法实现的。
有时为了提高效率,如果您想修改列表内容,可能更愿意避免复制。例如,假设您的列表包含大小为1KB的记录。如果要在不使用List
属性的情况下修改每个记录中的单个布尔值,最终会将整个1KB记录复制两次。只是修改一个布尔值。
当然,获取对底层存储的访问权限的成本是您接触到内部实现细节。 Embarcadero可以实现以更安全的方式为您提供访问权限的功能,但无论出于何种原因,他们都选择了这条路线。我想我可能已经创建了一个索引属性,它返回一个指向项目的指针。
所以,这确实是List
属性的唯一用例。除非您确实需要直接访问底层存储,否则请勿使用List
。当然,如果文档不愿解释任何这一点,那就太好了,但确实如此。
TList<T>
是否有实际的枚举数?
是的。
var
Item: SomeType;
MyList: TList<SomeType>;
....
for Item in MyList do
Item.Foo();
答案 1 :(得分:-1)
尝试将其更改为
for Item in oList do begin
Writeln(Item.ClassName);
end;
不确定为什么列表可用,但不要使用它。它只是一个数组,其中一些项目可以是零。
编辑:
.List的使用失败示例:
type
TItem = class
text : string;
constructor Create(AText : string);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
oList: TObjectList<TItem>;
Item: TItem;
begin
oList := TObjectList<TItem>.Create;
oList.Add(TItem.Create('a'));
oList.Add(TItem.Create('b'));
oList.Add(TItem.Create('c'));
// Add items to oList
for Item in oList.List do begin
memo1.lines.add(item.text);
end;
end;
constructor TItem.Create(AText: string);
begin
self.text := AText;
end;