如何在Delphi 10.1柏林中将嵌套对象转换为Json

问题描述

我在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;

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...