5

我想在 Delphi XE5 中使用带有子列表的通用 TList 记录:

type
  TMyRecord=record
    Value1: Real;
    SubList: TList<Integer>;
  end;

  TMyListOfRecords=TList<TMyRecord>;

var
  MyListOfRecords: TMyListOfRecords;

无法对记录的字段进行分配:

MyListOfRecords[0].Value1:=2.24; 

或者

MyListOfRecords[0].SubList:=TList<Integer>.Create;

将导致编译器“无法分配左侧”错误。

另请参阅:如何修改 TList<record> 值?

以下解决方法有效:

AMyRecord:=MyListOfRecords[0];
AMyRecord.Value1:=2.24;
AMyRecord.SubList:=TList<Integer>.Create;
AMyRecord.SubList.Add(33);
MyListOfRecords[0]:=AMyRecord;

由于性能问题,我想避免将数据复制到临时 AMyrecord。我宁愿直接访问记录字段和子列表。

处理这个问题的最佳方法是什么?

4

1 回答 1

6

List该列表通过该属性公开其内部存储,这是一个动态数组。所以你可以写:

MyListOfRecords.List[0].Value1 := 2.24; 

与具有价值副本的替代方案相比,这是否会在性能上产生任何可衡量的差异,我无法确定。值得检查一下。

正如@LURD 正确所说,List返回内部存储。这可能不止有Count元素。具体来说,它有Capacity元素。因此,如果您使用它,则必须使用数组索引访问元素,而0不是Count-1. 还要记住,对列表大小的修改可能涉及重新分配,因此内部存储可能会移动。您引用的任何参考List仅在下一次重新分配之前有效。

这些警告应建议您仅List在性能限制要求时才考虑使用。即便如此,也要谨慎使用它。

在我的代码库中,我有一个替代方法,TList<T>它的Items[]属性返回一个指向元素的指针。容器仍以动态数组的形式存储,以实现高效的内存布局。我更喜欢这个选项而不是List属性,因为我觉得它导致代码更简洁。


好的,您要求查看我的返回元素指针的列表类。这里是:

type
  TReferenceList<T> = class(TBaseValueList<T>)
  type
    P = ^T;
  private
    function GetItem(Index: Integer): P;
  public
    property Items[Index: Integer]: P read GetItem; default;
  public
    // .... helper types for enumerators excised
  public
    function GetEnumerator: TEnumerator;
    function Enumerator(Forwards: Boolean): TEnumeratorFactory;
    function ReverseEnumerator: TEnumeratorFactory;
    function IndexedEnumerator: TIndexedEnumeratorFactory;
  end;

现在,需要一些解释。基类TBaseValueList<T>是我的替代品TList<T>TList<T>如果你愿意,你可以替代。我没有,因为我的基类没有Items属性。那是因为我希望专门的课程来介绍它。我的另一个专业是:

type
  TValueList<T> = class(TBaseValueList<T>)
  private
    function GetItem(Index: Integer): T;
    procedure SetItem(Index: Integer; const Value: T);
  public
    property Items[Index: Integer]: T read GetItem write SetItem; default;
  end;

my 的实现TBaseValueList<T>非常明显。它与 非常相似TList<T>。我不认为你真的需要看到任何实现。这一切都非常明显。

作为获取元素引用的一种简单方法,您可以这样总结List

type
  TMyList<T> = class(TList<T>)
  public
    type
      P = ^T;
  private
    function GetRef(Index: Integer): P;
  public
    property Ref[Index: Integer]: P read GetRef;
  end;

function TMyList<T>.GetRef(Index: Integer): P;
begin
  Result := @List[Index];
end;

如果您想要比 Delphi 提供的更丰富的容器集,您可能会关注 Spring4D。虽然我不确定他们是否有像我的容器那样返回引用的东西。

于 2014-03-06T07:10:46.883 回答