【问题标题】:How to convert nested object into Json in Delphi 10.1 berlin如何在 Delphi 10.1 berlin 中将嵌套对象转换为 Json
【发布时间】:2020-10-05 18:26:02
【问题描述】:

我对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”。

提前谢谢你。

【问题讨论】:

  • 请您将错误消息作为问题的一部分和文本,而不是屏幕截图。
  • @RichardHunter 是的,先生。从下次开始,我将在文本中添加错误消息。非常感谢。

标签: json delphi json-serialization


【解决方案1】:

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

【讨论】:

  • 谢谢@Andreas Rejbrand。我忘记创建 Address 对象真是太愚蠢了。这篇文章对像我这样的初学者很有帮助。
猜你喜欢
  • 2019-09-01
  • 1970-01-01
  • 2019-07-04
  • 1970-01-01
  • 1970-01-01
  • 2016-12-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多