填充指向派生类字段的本地数组,但后面的字段为空

时间:2013-08-19 15:04:45

标签: delphi delphi-xe2 superobject

我必须在网络服务中忽略某些内容......

数据结构:

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;

然后是

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;)
    );

我的WebModule上有一个私有字段:

FResponse: TResBase;     // Response object

在WebmoduleBeforeDispatch中,FWebAct是一个ttgetlist,我这样做:

lResponseClass := cWebActStructures[FWebAct].ResponseClass;
FResponse      := lResponseClass.Create(lResponseClass.ClassName);  
// FResponse.ClassName is TResGetList, OK

在处理'ttgetlist'的TWebActionItem的OnAction处理程序中,这是必不可少的部分:

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此时显示正确的数据,对象检查器显示:

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

在WebmoduleAfterDispatch中:

var lJSO: ISuperObject;
begin
   lJSO := FResponse.ToJson;

LJSO.AsString确实有正确的字段(& type,success,... activities,...),例如success = 1,但活动为空

{
"errormessage":"",
"success":1,
"projects":[],
"threadid":1556,
"type":"ttgetlistresult",
"customers":[],
"activities":[]
}

我在俯瞰什么?也许OnAction处理程序中的lListArr := (FResponse as TResGetList).activities不够好吗?

BTW随意更新问题标题,这是我能想到的最好的。

1 个答案:

答案 0 :(得分:3)

分配lListArr时,局部变量会将引用接收到activities字段引用的同一个数组。但是,当您致电SetLength(lListArr, ...)时,会使lListArr引用 new 数组,与之前引用的数组完全分开。

如果希望字段引用同一个数组,则需要将其分配回字段:

(FResponse as TResGetList).activities := lListArr;

您可以在设置长度后随时进行该分配。通过任一变量都可以看到更改数组的内容。但是,更改长度与更改内容不同。更改长度会重新分配整个数组,并提供一个新的唯一数组。