问题描述
我在delphi中非常新。目前,我正面临一个问题。我想使用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时,会出现访问冲突错误。这是图片-access violation error image
[更新] 基本上,我收到“访问冲突在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;