2

根据我对这个主题的有限知识,以下代码应该可以工作。但我没有预期的结果:

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 和“”(空)

请问,我错过了什么?

谢谢!

4

1 回答 1

9
List := Clients.LockList;
try
  Clients.Add(Client); // <--- mistake here
finally
  Clients.UnlockList;
end;

习惯用法是您通过调用锁定列表LockList并返回一个可变列表。所以你需要打电话AddList

List := Clients.LockList;
try
  List.Add(Client);
finally
  Clients.UnlockList;
end;

也就是说,TThreadList确实提供了Add一种内部使用的方法LockList。您调用Add失败的原因是您使用了默认值Duplicatesis dupIgnore。而且您每次都传递相同的内存地址。

为什么每次的内存地址都一样?好吧,您犯的另一个错误是销毁您的TClient对象并稍后引用它们。我猜内存管理器正在重新使用您刚刚释放的内存。

您可能希望设置DuplicatesdupAccept. 至少你需要意识到它有潜在的影响。

这个程序产生你想要的输出:

{$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.
于 2014-12-18T20:50:59.683 回答