json - 如何在 Delphi 10.1 berlin 中将嵌套对象转换为 Json
问题描述
我对德尔福非常陌生。目前我面临一个问题。我想使用 TJson 将嵌套对象转换为 Json,但存在与内存相关的问题。
这是我的代码。
它只是带有 Person 和 Address 类的简单单元文件。人员类取决于地址类。
unit uPerson;
interface
uses
REST.Json;
type
TAddress = class
private
FStreetNAme: string;
FState: string;
FPinCode: string;
published
property StreetNAme: string read FStreetNAme write FStreetNAme;
property State: string read FState write FState;
property PinCode: string read FPinCode write FPinCode;
end;
TPerson = class
private
FName: string;
FAge: Integer;
FSalary: Double;
[JSONMarshalled(True)]
FAddress: TAddress;
published
property Name: string read FName write FName;
property Age: Integer read FAge write FAge;
property Salary: Double read FSalary write FSalary;
property Address: TAddress read FAddress write FAddress;
end;
implementation
end.
下面是主要的表单代码
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, uPerson,
REST.JSON;
type
TForm1 = class(TForm)
edtName: TLabeledEdit;
edtAge: TLabeledEdit;
edtSalary: TLabeledEdit;
edtStreet: TLabeledEdit;
edtState: TLabeledEdit;
edtPin: TLabeledEdit;
btnSave: TButton;
Memo1: TMemo;
procedure btnSaveClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Person: TPerson;
Add: TAddress;
implementation
{$R *.dfm}
procedure TForm1.btnSaveClick(Sender: TObject);
var
jsonString: string;
begin
Person := TPerson.Create;
try
Person.Name := edtName.Text;
Person.Age := Integer.Parse(edtAge.Text);
Person.Salary := double.Parse(edtSalary.Text);
Add.StreetNAme := edtStreet.Text;
Add.State := edtState.Text;
Add.PinCode := edtPin.Text;
Person.Address := Add;
jsonString := TJson.ObjectToJsonString(Person);
Memo1.Text := jsonString;
finally
Add.Free;
Person.Free;
end;
//
end;
end.
代码正在正确编译。但是当尝试生成 json 时,它会给出访问冲突错误。这是图像 -访问冲突错误图像
[更新] 基本上我得到“0x00409fca 的访问冲突:写地址 0x00000004”。
先感谢您。
解决方案
我对 JSON 工具一无所知,但我知道 Delphi 内存管理。
这个错误是意料之中的,因为你忘记了创建TAddress
对象。
第一个问题是这一行:
Add.StreetNAme := edtStreet.Text;
Add
是一个全局变量,所以它最初被设置为nil
(因为它是一个对象指针)。因此,您在这里尝试写入非常接近 的内存地址0
,这正是您在异常消息中看到的内容。
您需要TAddress
在堆上创建一个对象并将该对象的地址分配给Add
变量。
就像您为TPerson
对象所做的那样。
procedure TForm1.btnSaveClick(Sender: TObject);
var
jsonString: string;
begin
Person := TPerson.Create;
try
Add := TAddress.Create;
try
Person.Name := edtName.Text;
Person.Age := Integer.Parse(edtAge.Text);
Person.Salary := double.Parse(edtSalary.Text);
Add.StreetName := edtStreet.Text;
Add.State := edtState.Text;
Add.PinCode := edtPin.Text;
Person.Address := Add;
jsonString := TJson.ObjectToJsonString(Person);
Memo1.Text := jsonString;
finally
Add.Free;
end;
finally
Person.Free;
end;
end;
此外,在这里使用全局变量也不是一个好主意。相反,使用局部变量。而且根本不需要单独的TAddress
变量:
var
Person: TPerson;
jsonString: string;
begin
Person := TPerson.Create;
try
Person.Address := TAddress.Create;
try
Person.Name := edtName.Text;
Person.Age := Integer.Parse(edtAge.Text);
Person.Salary := double.Parse(edtSalary.Text);
Person.Address.StreetName := edtStreet.Text;
Person.Address.State := edtState.Text;
Person.Address.PinCode := edtPin.Text;
jsonString := TJson.ObjectToJsonString(Person);
Memo1.Text := jsonString;
finally
Person.Address.Free;
end;
finally
Person.Free;
end;
end;
TPerson
此外,您可能会争辩说,如果构造函数创建一个TAddress
对象并将指向它的指针放在其Address
字段中会更好。然后TPerson
析构函数也将负责释放这个对象:
unit uPerson;
interface
uses
REST.Json;
type
TAddress = class
private
FStreetNAme: string;
FState: string;
FPinCode: string;
published
property StreetNAme: string read FStreetNAme write FStreetNAme;
property State: string read FState write FState;
property PinCode: string read FPinCode write FPinCode;
end;
TPerson = class
private
FName: string;
FAge: Integer;
FSalary: Double;
[JSONMarshalled(True)]
FAddress: TAddress;
public
constructor Create;
destructor Destroy; override;
published
property Name: string read FName write FName;
property Age: Integer read FAge write FAge;
property Salary: Double read FSalary write FSalary;
property Address: TAddress read FAddress write FAddress;
end;
implementation
{ TPerson }
constructor TPerson.Create;
begin
FAddress := TAddress.Create;
end;
destructor TPerson.Destroy;
begin
FAddress.Free;
inherited;
end;
end.
和
var
Person: TPerson;
jsonString: string;
begin
Person := TPerson.Create;
try
Person.Name := 'Andreas';
Person.Age := 32;
Person.Salary := 12345;
Person.Address.StreetName := 'Street';
Person.Address.State := 'State';
Person.Address.PinCode := 'pin';
jsonString := TJson.ObjectToJsonString(Person);
Memo1.Text := jsonString;
finally
Person.Free;
end;
end;