2

TListBox 组件包含一组行(字符串)。如何将此集合作为列表 TList ?下面的代码示例没有给出预期的结果。(Сode 无法编译)

MyList  := TList<String>.Create(MyListBox);
MyList  := TList<String>.Create(MyListBox.Items);
MyList  := TList<String>.Create(MyListBox.Items.ToStringArray);

是否可以在不使用循环的情况下做到这一点?谢谢!

4

2 回答 2

5

你可以这样做:

MyList := TList<string>.Create;
try
  MyList.AddRange(MyListBox.Items.ToStringArray);
  ....
finally
  MyList.Free;
end;

如果你想在构造函数中分配项目,你需要一个TEnumerable<string>. 这并不容易TStrings从外部嫁接。所以我认为上面的代码可能是最干净的。

于 2013-08-08T08:56:40.933 回答
3

大卫的答案很简单,如果您不介意分配一个额外的数组来保存正在复制的字符串的临时副本。如果你想减少内存使用,特别是如果列表很大,循环会更好:

var
  MyList: TList<String>;
  I: Integer;
begin
  MyList := TList<String>.Create;
  try
    MyList.Capacity := MyListBox.Items.Count;
    for i := 0 to MyList.Capacity-1 do
      MyList.Add(MyListBox.Items[I]);
    ...
  finally
    MyList.Free;
  end;
end;

或者:

var
  MyList: TList<String>;
  S: String;
begin
  MyList := TList<String>.Create;
  try
    MyList.Capacity := MyListBox.Items.Count;
    for S in MyListBox.Items do
      MyList.Add(S);
    ...
  finally
    MyList.Free;
  end;
end;

但是,如果您不想手动循环,那么我建议您创建一个自定义枚举器,以便您可以将TStrings数据直接传递给TList<String>并让它为您复制字符串:

type
  TStringsEnumeratorWrapper = class(TEnumerator<String>)
  protected
    FEnum: TStringsEnumerator;
    function DoGetCurrent: String; override;
    function DoMoveNext: Boolean; override;
  public
    constructor Create(AStrings: TStrings);
    destructor Destroy; override;
  end;

constructor TStringsEnumeratorWrapper.Create(AStrings: TStrings);
begin
  inherited Create;
  FEnum := AStrings.GetEnumerator;
end;

destructor TStringsEnumeratorWrapper.Destroy;
begin
  FEnum.Free;
  inherited Destroy;
end;

function TStringsEnumeratorWrapper.DoGetCurrent: String;
begin
  Result := FEnum.Current;
end;

function TStringsEnumeratorWrapper.DoMoveNext: Boolean;
begin
  Result := FEnum.MoveNext;
end;

type
  TStringsEnumerableWrapper = class(TEnumerable<String>)
  protected
    FStrings: TStrings;
    function DoGetEnumerator: TEnumerator<T>; override;
  public
    constructor Create(AStrings: TStrings);
  end;

constructor TStringsEnumerableWrapper.Create(AStrings: TStrings);
begin
  inherited Create;
  FStrings := AStrings;
end;

function TStringsEnumerableWrapper.DoGetEnumerator: TEnumerator<T>;
begin
  Result := TStringsEnumeratorWrapper.Create(FStrings);
end;

var
  MyList: TList<String>;
  Enum: TStringsEnumerableWrapper;
begin
  MyList := TList<String>.Create;
  try
    MyList.Capacity := MyListBox.Items.Count;
    Enum := TStringsEnumerableWrapper.Create(MyListBox.Items);
    try
      MyList.AddRange(Enum);
    finally
      Enum.Free;
    end;
    ...
  finally
    MyList.Free;
  end;
end;

或者:

type
  TStringsEnumeratorWrapper = class(TObject, IEnumerator<String>)
  protected
    FEnum: TStringsEnumerator;
  public
    constructor Create(AStrings: TStrings);
    destructor Destroy; override;
    function GetCurrent: String;
    function MoveNext: Boolean;
    procedure Reset;
  end;

constructor TStringsEnumeratorWrapper.Create(AStrings: TStrings);
begin
  inherited Create;
  FEnum := AStrings.GetEnumerator;
end;

destructor TStringsEnumeratorWrapper.Destroy;
begin
  FEnum.Free;
  inherited Destroy;
end;

function TStringsEnumeratorWrapper.GetCurrent: String;
begin
  Result := FEnum.Current;
end;

function TStringsEnumeratorWrapper.MoveNext: Boolean;
begin
  Result := FEnum.MoveNext;
end;

procedure TStringsEnumeratorWrapper.Reset;
begin
  //FEnum.Reset;
end;

type
  TStringsEnumerableWrapper = class(TObject, IEnumerable<String>)
  protected
    FStrings: TStrings;
  public
    constructor Create(AStrings: TStrings);
    function GetEnumerator: IEnumerator<String>;
  end;

constructor TStringsEnumerableWrapper.Create(AStrings: TStrings);
begin
  inherited Create;
  FStrings := AStrings;
end;

function TStringsEnumerableWrapper.GetEnumerator: IEnumerator<String>;
begin
  Result := TStringsEnumeratorWrapper.Create(FStrings);
end;

var
  MyList: TList<String>;
begin
  MyList := TList<String>.Create;
  try
    MyList.Capacity := MyListBox.Items.Count;
    MyList.AddRange(TStringsEnumerableWrapper.Create(MyListBox.Items));
    ...
  finally
    MyList.Free;
  end;
end;

诚然,不像大卫的回答那样优雅,但枚举器旨在帮助更轻松地循环遍历列表项(因此允许创建for..in循环语法)。

于 2013-08-09T03:43:18.427 回答