Список тем TObject с Delphi - Как заполнить?
Исходя из моих ограниченных знаний об этом предмете, следующий код должен работать. Но у меня нет ожидаемого результата:
type
TClient = class(TObject)
Host: String;
end;
var
Clients: TThreadList;
const
Hosts: Array[0..5] of String = ('HOST1', 'HOST2', 'HOST3', 'HOST4', 'HOST5', 'HOST6');
var
I: Integer;
List: TList;
Client: TClient;
begin
try
for I := Low(Hosts) to High(Hosts) do
begin
Client := TClient.Create;
with Client Do
try
Host := Hosts[I];
List := Clients.LockList;
try
Clients.Add(Client);
finally
Clients.UnlockList;
end;
finally
Client.Free;
end;
end;
except
on E:Exception Do ShowMessage(E.Message);
end;
// RESULT TEST
List := Clients.LockList;
try
I := List.Count;
S := TClient(List.Items[0]).Host;
finally
Clients.UnlockList;
end;
ShowMessage(IntToStr(I));
ShowMessage(S);
Мой ожидаемый результат будет 6 и HOST1, но я получил 1 и "" (пусто)
Пожалуйста, чего мне не хватает?
Спасибо!
1 ответ
List := Clients.LockList;
try
Clients.Add(Client); // <--- mistake here
finally
Clients.UnlockList;
end;
Идиома в том, что вы блокируете список с помощью вызова LockList
и это возвращает изменчивый список. Так что вам нужно позвонить Add
на List
,
List := Clients.LockList;
try
List.Add(Client);
finally
Clients.UnlockList;
end;
Это сказало, TThreadList
действительно предлагает Add
метод, который внутренне использует LockList
, Причина того, что ваш призыв к этому Add
не удалось в том, что вы использовали значение по умолчанию Duplicates
который dupIgnore
, И каждый раз вы передавали один и тот же адрес памяти.
Почему адрес памяти был одинаковым каждый раз? Ну, другая ошибка, которую вы сделали, это уничтожить вашу TClient
объекты и обратитесь к ним позже. Я думаю, что менеджер памяти повторно использовал память, которую вы только что освободили.
Вы можете установить Duplicates
в dupAccept
, По крайней мере, вы должны знать, что это имеет потенциальное влияние.
Эта программа производит желаемый результат:
{$APPTYPE CONSOLE}
uses
SysUtils, Classes;
type
TClient = class(TObject)
Host: String;
end;
const
Hosts: Array[0..5] of String = ('HOST1', 'HOST2', 'HOST3', 'HOST4',
'HOST5', 'HOST6');
var
I: Integer;
List: TList;
Client: TClient;
Clients: TThreadList;
begin
Clients := TThreadList.Create;
Clients.Duplicates := dupAccept;
for I := Low(Hosts) to High(Hosts) do
begin
Client := TClient.Create;
Client.Host := Hosts[I];
List := Clients.LockList;
try
List.Add(Client);
finally
Clients.UnlockList;
end;
end;
List := Clients.LockList;
try
Writeln(List.Count);
Writeln(TClient(List.Items[0]).Host);
finally
Clients.UnlockList;
end;
end.
Или цикл может быть упрощен еще больше:
for I := Low(Hosts) to High(Hosts) do
begin
Client := TClient.Create;
Client.Host := Hosts[I];
Clients.Add(Client);
end;
Я упустил возможность делать какие-либо освобождения ради более простой экспозиции. Очевидно, что в реальном коде вы бы не пропустили то, что делает этот код.
Лично я не фанат этого класса. Не в этом веке дженериков. Вы действительно должны смотреть на TThreadList<T>
,
{$APPTYPE CONSOLE}
uses
SysUtils, Classes, Generics.Collections;
type
TClient = class
Host: string;
constructor Create(AHost: string);
end;
constructor TClient.Create(AHost: string);
begin
inherited Create;
Host := AHost;
end;
const
Hosts: array[0..5] of string = ('HOST1', 'HOST2', 'HOST3', 'HOST4',
'HOST5', 'HOST6');
var
Host: string;
List: TList<TClient>;
Clients: TThreadList<TClient>;
begin
Clients := TThreadList<TClient>.Create;
Clients.Duplicates := dupAccept;
for Host in Hosts do
Clients.Add(TClient.Create(Host));
List := Clients.LockList;
try
Writeln(List.Count);
Writeln(List.First.Host);
finally
Clients.UnlockList;
end;
end.