Как преобразовать вложенный объект в Json в Delphi 10.1 berlin

Я очень новичок в делфи. На данный момент столкнулся с проблемой. я хочу преобразовать вложенный объект в Json, используя TJson, но имею проблему, связанную с памятью.

Вот мой код.

Это просто простой модульный файл с классом 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.

Заранее спасибо.


person SP Sarkar    schedule 05.10.2020    source источник
comment
Пожалуйста, не могли бы вы включить сообщение об ошибке как часть вопроса и в тексте, а не скриншот.   -  person Richard Hunter    schedule 05.10.2020
comment
@RichardHunter да, сэр. Со следующего раза я добавлю сообщение об ошибке в тексте. Большое тебе спасибо.   -  person SP Sarkar    schedule 06.10.2020


Ответы (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;
person Andreas Rejbrand    schedule 05.10.2020
comment
Спасибо @Андреас Рейбранд. Глупо с моей стороны, что я забыл создать объект Address. Пост есть и будет полезен новичкам вроде меня. - person SP Sarkar; 06.10.2020