我想在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;

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

另请参阅:How to modify TList<record> value?

以下变通办法起作用:
AMyRecord:=MyListOfRecords[0];
AMyRecord.Value1:=2.24;
AMyRecord.SubList:=TList<Integer>.Create;
AMyRecord.SubList.Add(33);
MyListOfRecords[0]:=AMyRecord;

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

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

最佳答案

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

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

我无法确定这与带有值副本的替代方案相比在性能上是否有可衡量的差异。值得检查一下。

就像@LURD正确说的那样,List返回内部存储。而且它可能不止Count元素。具体来说,它具有Capacity元素。因此,如果使用它,则必须使用数组索引从元素0Count-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属性。那是因为我希望专门的类(class)来介绍它。我的另一个专长是:
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;

我的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。尽管我不确定它们是否像我的容器那样返回引用。

关于delphi - 带有子列表的记录的通用TList?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22212783/

10-09 06:36