How can I use the Move procedure to populate a TList <T> Element?

I need to move data stored in a byte array to a set of records located in a TList, but I get this error

E2197 Constant object cannot be passed as var parameter

This code reproduces the problem.

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. 

How can I copy the contents of a buffer to a TList element

+4
source share
2 answers

In XE2, the internal storage for TList<T> opaque and hidden. You cannot access it in the usual ways. All access to the list items is copied - links to the underlying storage are not available. So you cannot blit to it using Move . If you need a structure that you can connect to, you should consider the dynamic array TArray<T> .

You can always use the trick to implement a helper class class for TList<TData> , which will output the private variable FItems . These are pretty hacks, but will do what you ask.

 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; 

I think you could put some parameter checking in TListTDataHelper.Blit , but I will leave it to you.

If you use XE3, you can access the TList<T> private repository using the List property.

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

If you do not need blit and you can use the for loop, do the following:

 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; 

But I interpret your question that you want to avoid this option.

+4
source

Instead of using Move() try using the TList<T>.Items[] property installer instead, and let the compiler and RTL handle the copy for you:

 type PData = ^TData; ... List[0] := PData(@P[0])^; 
+1
source

All Articles