4

我需要将存储在字节数组中的数据移动到位于 TList 中的一组记录中,但出现此错误

E2197 常量对象不能作为 var 参数传递

此代码重现了该问题。

uses
  System.Generics.Collections,
  System.SysUtils;

type
  TData = record
    Age : Byte;
    Id  : Integer;
  end;

//this code is only to show the issue, for simplicity i'm filling only the first  
//element of the TList but the real code needs fill N elements from a very big array.  
var
  List : TList<TData>;
  P : array [0..1023] of byte;
begin
  try
    List:=TList<TData>.Create;
    try
      List.Count:=1;
      //here i want to move the content of the P variable to the element 0
      Move(P[0],List[0], SizeOf(TData));

    finally
      List.Free;
    end;

  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

我如何将缓冲区的内容复制到 TList 元素

4

2 回答 2

3

在 XE2 中,内部存储TList<T>是不透明和隐藏的。您无法通过正常方式访问它。对列表元素的所有访问都被复制——对底层存储的引用不可用。所以你不能使用Move. 如果你想要一个可以blit到的结构,你应该考虑一个动态数组,TArray<T>.

您总是可以使用实现类助手的技巧来TList<TData>公开私有变量FItems。这很hacky,但会按照你的要求做。

type
  __TListTData = TList<TData>;
  //defeat E2086 Type 'TList<T>' is not yet completely defined

type
  TListTDataHelper = class helper for TList<TData>
    procedure Blit(const Source; Count: Integer);
  end;

procedure TListTDataHelper.Blit(const Source; Count: Integer);
begin
  System.Move(Source, Pointer(FItems)^, Count*SizeOf(Self[0]));
end;

我猜你可能想在里面加入一些参数检查TListTDataHelper.Blit,但我会把它留给你。

如果您使用的是 XE3,则可以TList<T>使用该List属性访问私有存储。

Move(P, Pointer(List.List)^, N*SizeOf(List[0]));

如果您不需要 blit 并且可以使用 for 循环,请执行以下操作:

type
  PData = ^TData;
var
  i: Integer;
  Ptr: PData;
....
List.Count := N;
Ptr := PData(@P);
for i := 0 to List.Count-1 do
begin
  List[i] := Ptr^;
  inc(Ptr);
end;

但我将您的问题解释为您希望避免此选项。

于 2013-01-15T23:00:08.233 回答
1

而不是 using Move(),而是尝试使用TList<T>.Items[]属性设置器,让编译器和 RTL 为您处理复制:

type
  PData = ^TData;
  ...

List[0] := PData(@P[0])^;
于 2013-01-16T01:35:46.157 回答