首页 文章

具有子列表的记录的通用TList?

提问于
浏览
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;

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

另见: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 . 我宁愿直接访问记录字段和子列表 .

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

1 回答

  • 6

    该列表通过List属性公开其内部存储(动态数组) . 所以你可以写:

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

    与具有 Value 副本的替代方案相比,这是否会在性能方面产生任何可衡量的差异,我无法分辨 . 值得检查一下 .

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

    这些警告应该告诉您,如果性能限制要求,您只考虑使用 List . 即使这样,也要谨慎使用它 .

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


    好的,你要求查看我的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;
    

    我的 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 . 虽然我不确定他们是否有类似我的容器返回引用 .

相关问题