当前位置: 动力学知识库 > 问答 > 编程问答 >

delphi - Fill local array pointing to field of derived class, but later field empty

问题描述:

I must be overlooking something in my web service...

Data structures:

TResIDNameRec = record

id : Integer;

name: String;

end;

TResIDNameArr = array of TResIDNameRec;

TResBase = class(TJSONStructure) // just a class(TObject)

private

public

&type : String;

success : Integer;

errormessage: String;

threadid : Integer;

constructor Create; overload; // empty

constructor Create(ADescendantClassName: String); overload; // sets &type

end;

TResClass = class of TResBase;

TResGetList = class(TResBase)

private

public

activities,

projects,

customers: TResIDNameArr;

constructor Create; overload; // inherited Create(Self.ClassName);

end;

and then a

type

TWebAct = (

ttlogin,

...

ttgetlist,

...

ttgetversion

);

const

cWebActStructures: Array[TWebAct] of

record

RequestClass : TReqClass;

ResponseClass: TResClass;

end

= (

{ ttlogin } (RequestClass: TReqLogin; ResponseClass: TResLogin;),

...

{ ttgetlist } (RequestClass: TReqGetList; ResponseClass: TResGetList;),

...

{ ttgetversion} (RequestClass: TReqGetVersion; ResponseClass: TResGetVersion;)

);

I have a private field on my WebModule:

FResponse: TResBase; // Response object

In the WebmoduleBeforeDispatch, FWebAct is a ttgetlist, and I do:

lResponseClass := cWebActStructures[FWebAct].ResponseClass;

FResponse := lResponseClass.Create(lResponseClass.ClassName);

// FResponse.ClassName is TResGetList, OK

In the OnAction handler for the TWebActionItem that handles the 'ttgetlist', here is the essential part:

var

lListArr : TResIDNameArr;

begin

lListArr := (FResponse as TResGetList).activities;

with AClientDataSet do

begin

Open;

SetLength(lListArr,RecordCount); // Pre-allocate (currently 152)

l := 0;

First;

while not EOF do

begin

if SomeConditionMet then

begin

lListArr[l].id := FieldByName(lIDVeld).AsInteger;

lListArr[l].name := FieldByName(SName).AsString;

Inc(l);

end;

Next;

end;

Close;

SetLength(lListArr,l+1); // Adjust (l is now 108)

end;

FResponse.success := 1;

lListArr shows correct data at this moment, object inspector shows:

((3, 'Activiteit 3'), (4, 'Activiteit 3.1'), (5, 'Activiteit 3.2'), (10, 'Activiteit 3.3'), (8, 'Activiteit 5'),...

In WebmoduleAfterDispatch:

var lJSO: ISuperObject;

begin

lJSO := FResponse.ToJson;

LJSO.AsString does have the correct fields (&type, success, ... activities, ... ), and e.g. success=1, but activities is empty:

{

"errormessage":"",

"success":1,

"projects":[],

"threadid":1556,

"type":"ttgetlistresult",

"customers":[],

"activities":[]

}

What am I overlooking? Is maybe the lListArr := (FResponse as TResGetList).activities in the OnAction handler 'not good enough'?

BTW Feel free to update the question title, this was the best I could come up with.

网友答案:

When you assign lListArr, the local variable receives a reference to the same array that the activities field references. However, when you call SetLength(lListArr, ...), that makes lListArr refer to a new array, completely separate from the one it referenced before.

If you want the field to refer to the same array, you need to assign it back to the field:

(FResponse as TResGetList).activities := lListArr;

You can make that assignment at any time after the length has been set. Changes the the contents of the array will be visible through either variable. Changing the length is not the same as changing the contents, though. Changing the length re-allocates the entire array and gives a new, unique array.

分享给朋友:
您可能感兴趣的文章:
随机阅读: