我想知道这个方法调用是做什么的:
stringList.addObject(String,Object);
我也想知道这个属性是做什么用的:
stringList.Objects[i]
在添加时看起来是键值对,但在循环中检索时会检索到什么?
我还看到了items[i]的调用。
我对TStringList操作和TList操作感到困惑。
我想知道这个方法调用是做什么的:
stringList.addObject(String,Object);
我也想知道这个属性是做什么用的:
stringList.Objects[i]
在添加时看起来是键值对,但在循环中检索时会检索到什么?
我还看到了items[i]的调用。
我对TStringList操作和TList操作感到困惑。
TStringList.Strings
列表中的条目,以及一个匹配的 TObject
在 TStringList.Objects
列表中。type
TPerson=class
FFirstName, FLastName: string;
FDOB: TDateTime;
FID: Integer;
private
function GetDOBAsString: string;
function GetFullName: string;
published
property FirstName: string read FFirstName write FFirstName;
property LastName: string read FLastName write FLastName;
property DOB: TDateTime read FDOB write FDOB;
property DOBString: string read GetDOBAsString;
property FullName: string read GetFullName;
property ID: Integer read FID write FID;
end;
implementation
{TPerson}
function TPerson.GetDOBAsString: string;
begin
Result := 'Unknown';
if FDOB <> 0 then
Result := DateToStr(FDOB);
end;
function TPerson.GetFullName: string;
begin
Result := FFirstName + ' ' + FLastName; // Or FLastName + ', ' + FFirstName
end;
var
PersonList: TStringList;
Person: TPerson;
i: Integer;
begin
PersonList := TStringList.Create;
try
for i := 0 to 9 do
begin
Person := TPerson.Create;
Person.FirstName := 'John';
Person.LastName := Format('Smith-%d', [i]); // Obviously, 'Smith-1' isn't a common last name.
Person.DOB := Date() - RandRange(1500, 3000); // Make up a date of birth
Person.ID := i;
PersonList.AddObject(Person.LastName, Person);
end;
// Find 'Smith-06'
i := PersonList.IndexOf('Smith-06');
if i > -1 then
begin
Person := TPerson(PersonList.Objects[i]);
ShowMessage(Format('Full Name: %s, ID: %d, DOB: %s',
[Person.FullName, Person.ID, Person.DOBString]));
end;
finally
for i := 0 to PersonList.Count - 1 do
PersonList.Objects[i].Free;
PersonList.Free;
end;
这显然是一个刻意编造的例子,因为它并不是你真正会发现有用的东西。不过它演示了这个概念。
另一个方便的用途是将整数值与字符串一起存储(例如,在 TComboBox
或 TListBox
中显示项目列表以及用于数据库查询的相应 ID)。在这种情况下,您只需将整数(或任何其他 SizeOf(Pointer))强制转换为 Objects
数组即可。
// Assuming LBox is a TListBox on a form:
while not QryItems.Eof do
begin
LBox.Items.AddObject(QryItem.Fields[0].AsString, TObject(QryItem.Fields[1[.AsInteger));
QryItems.Next;
end;
// User makes selection from LBox
i := LBox.ItemIndex;
if i > -1 then
begin
ID := Integer(LBox.Items.Objects[i]);
QryDetails.ParamByName('ItemID').AsInteger := ID;
// Open query and get info.
end;
如果存储的不是实际的 TObject
,则无需释放其内容。由于它们不是真正的对象,除了 TStringList
本身之外,没有其他需要释放的东西。
stringListB := stringListA
时,描述对象会发生什么将会很有帮助。stringListB.Objects
是否会复制指向原始对象的指针?这是否意味着当我们想要释放 stringListA
时,不应该逐个释放其分配的对象? - VassilisstringListB := stringListA;
不是复制;它将对stringListA
的引用分配给变量stringListB
。也就是说,它们是同一件事情,被两个变量引用。因为没有第二个字符串列表的副本,所以没有第二个Objects
的副本。如果这些对象不是真正的对象,那么没有理由释放任何东西(正如我答案的最后一段明确说明的那样)。 - Ken WhiteItems
是一个TListBox的属性吗?在这种情况下,它如何处理赋值?slA:= TStringList.create; slA.add('A'); ListBox1.Items:= slA; slA.Free; ShowMessage(ListBox1.Items [0]);
如果它只是一个引用,通过释放slA
,ListBox1.Items
不应该包含任何值(至少)。但是,如果我们使用另一个TStringList实例代替ListBox,则会像你说的那样导致代码崩溃。我的第一个问题是使用TListBox.Items
发展出来的。 - VassilisslA := TStringList.Create; slA.Add('A'); ListBox1.Items.Assign(slA); slA.Free;
是正确的方式(或者用 ListBox1.Items.AddStrings(slA);
替换 Assign
)。问题在于 Items := slA;
只是得到了 slA
的第二个引用(它们是同一个对象);因此,slA.Free;
使得 ListBox1.Items
中包含的引用无效,因为它们是同一件事情。我在上一条评论中已经说过了。如果您需要更多关于这些内容如何工作的信息,请发布自己的新问题;这不适合在本问题的评论中讨论。 - Ken WhiteAddObject
方法可以让你存储一个TObject地址 (指针),与存储在Item属性中的字符串相关联。而Objects
属性用于访问存储的对象。AddObject
来存储与每个字符串关联的整数值。var
List : TStringList;
I : integer;
begin
try
List:=TStringList.Create;
try
List.AddObject('Item 1', TObject(332));
List.AddObject('Item 2', TObject(345));
List.AddObject('Item 3', TObject(644));
List.AddObject('Item 4', TObject(894));
for I := 0 to List.Count-1 do
Writeln(Format('The item %d contains the string "%s" and the integer value %d',[I, List[I], Integer(List.Objects[i])]));
finally
List.Free;
end;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
Readln;
end.
OwnsObjects
属性(和构造函数参数)之前的Delphi版本,并且您不仅仅存储值而是实例引用,那么您必须在释放StringList本身之前释放任何放置在这些对象引用中的实例(除非当然这些实例被其他东西所拥有)。 - Marjan VenemaTStringList不仅仅是一个字符串列表。
它可以用于名称值对:
stringlist.Values['apple'] := 'one';
stringlist.Values['banana'] := 'two';
但是它也可以用于将字符串与任何对象(或任何指针)关联起来。
stringlist.AddObject('apple', TFruit.Create);
stringlist.AddObject('banana', TFruit.Create);
i := stringlist.IndexOf('apple');
if i >= 0 then
myfruit := stringlist.Objects[i] as TFruit;
TList是一个存储指针的列表,它们与字符串无关。
TFruit.Create
)必须被释放(例如 for i := 0 to stringlist.Count-1 do stringList.Objects[i].Free;
或 OwnsObjects
属性),并且不要使用 TStringList
来存储刚创建的对象。你可以将其与具有 VCL 管理所有权或具有自己生命周期的对象一起使用。因为 OP 似乎没有经验,所以你的答案应该至少提到这一点(就像 Ken White 的回答)。 - Arnaud Bouchez
TList<T>
取代了这种技术。 - David Heffernan