Список тем 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.
Другие вопросы по тегам