首页 > 解决方案 > 如何在 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”。

先感谢您。

标签: jsondelphijson-serialization

解决方案


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

推荐阅读