Дельфы Отдыхают.JSON JsonToObject работает только с переменными f

я использую Delphi XE8.

я просто смотрел на REST.Json ObjectToJsonString() и JsonToObject() звонки.

в основном пытается сделать что-то вроде этого:

как преобразовать объект в JSON и обратно с помощью одной строки кода

я заметил, что я мог заставить переменные работать только тогда, когда они начинались с F символ. Я не смог найти никаких документов. Это ожидаемое поведение? Должен ли я называть все переменные внутри моих классов с F в начале? Если да, может кто-нибудь объяснить, почему?

я создал класс TTestJSON и определил две переменные-члена и установил их в "WORKS" и "FAILS".

затем я создал строковое значение JSON из объекта:

{
  "varThatWorksBeacuseItStartsWithF":"WORKS",
  "sVarThatFailsBecauseItStartsWithS":"FAILS"
} 

возвращаясь от строки JSON к объекту, только fVarThatWorksBeacuseItStartsWithF переменная сбрасывается правильно. В приведенном ниже коде test := TJson.JsonToObject<TTestJSON>(JsonStr); используя вышеупомянутый JSON, обратите внимание, что sVarThatFailsBecauseItStartsWithS is "" и не "FAILS".

procedure TForm3.btn1Click(Sender: TObject);
var
  test : TTestJSON;
  JsonStr : String;
begin
  m1.Clear;
  test := TTestJSON.Create;
  try
    test.fVarThatWorksBeacuseItStartsWithF := 'WORKS';
    test.sVarThatFailsBecauseItStartsWithS := 'FAILS';
    JsonStr := TJson.ObjectToJsonString( test );
  finally
    test.Free;
  end;
  m1.Lines.Add(  '** JSONStr Value START **' + #13#10 + JsonStr + '** JSONStr Value END **' + #13#10 );

  test := TJson.JsonToObject<TTestJSON>(JsonStr);
  try
    m1.Lines.Add('** Obj loaded from JSON String Start **' + #13#10 + TJson.ObjectToJsonString( test ) + #13#10 + '** Obj loaded from JSON String End **');
  finally
    test.Free;
  end;
end;

из результатов, var, который начинается с f имеет f вырван из строки JSON, и тот, который начинается с s он все еще там. Я бы ожидал, что второй результат будет выглядеть так:

{
  "varThatWorksBeacuseItStartsWithF":"WORKS",
  "sVarThatFailsBecauseItStartsWithS":"FAILS"
}

вот полный код для воспроизведения-просто есть кнопка и памятка на форме vcl-также использует REST.В JSON:

unit Main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, rest.Json;

type
  TTestJSON = class
    fVarThatWorksBeacuseItStartsWithF : String;
    sVarThatFailsBecauseItStartsWithS : String;
  end;

  TForm3 = class(TForm)
    btn1: TButton;
    m1: TMemo;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.dfm}

procedure TForm3.btn1Click(Sender: TObject);
var
  test : TTestJSON;
  JsonStr : String;
begin
  m1.Clear;
  test := TTestJSON.Create;
  try
    test.fVarThatWorksBeacuseItStartsWithF := 'WORKS';
    test.sVarThatFailsBecauseItStartsWithS := 'FAILS';
    JsonStr := TJson.ObjectToJsonString( test );
  finally
    test.Free;
  end;
  m1.Lines.Add(  '** JSONStr Value START **' + #13#10 + JsonStr + '** JSONStr Value END **' + #13#10 );

  test := TJson.JsonToObject<TTestJSON>(JsonStr);
  try
    m1.Lines.Add('** Obj loaded from JSON String Start **' + #13#10 + TJson.ObjectToJsonString( test ) + #13#10 + '** Obj loaded from JSON String End **');
  finally
    test.Free;
  end;
end;

end.

2 ответов


сериализация JSON в Delphi основана на полях, а не на свойствах. Но большинство классов Delphi имеют дружественные свойства и F-префиксные поля. В то же время кажется, что Emb пытается избежать F-префиксных имен в сгенерированном JSON. Они отрезают первое " F " от имени при сериализации полей и добавляют его обратно (чтобы найти правильное поле) при чтении из JSON. Кажется, единственный (безопасный) способ использовать сериализацию JSON в Delphi-сохранить все имена полей с префиксом " F " (для полей, которые вы хотите serialize):

TTestJSON = class
protected
  FName: String;
public
  property Name: String read FName write FName;
end;

UPDATE2: как упоминает Дэвид, мы можем использовать атрибуты, а затем у нас есть гораздо лучший контроль:

uses
  REST.Json.Types, // without this unit we get warning: W1025 Unsupported language feature: 'custom attribute'
  REST.Json;

type
  // All fields of records are serialized, no control here.
  TRec = record
    RecStr: String;
  end;

  // By default all fields of class are serialized, but only F-prefixed serialized correctly.
  // We can use JSONMarshalled attribute to enable/disable serialization.
  // We can use JSonName attribute to serialize field with specific name in JSON.
  TTestJSON = class
    [JSONMarshalled(True)] [JSonName('RecField')]
    R: TRec;
  end;

procedure TForm28.FormCreate(Sender: TObject);
var
  Test: TTestJSON;
  JsonStr: string;
begin
  Test := TTestJSON.Create;
  try
    Test.R.RecStr := 'Some str';
    JsonStr := TJson.ObjectToJsonString( Test );
  finally
    FreeAndNil(Test);
  end;

  // JsonStr: {"RecField":["Some str"]}

  Test := TJson.JsonToObject<TTestJSON>(JsonStr);
  FreeAndNil(Test);
end;

эта библиотека для сериализации полей. Поскольку обычной практикой является префикс полей с буквой F, дизайнеры хотят удалить эту букву из имен, используемых в JSON. Поэтому они решили сделать поведение по умолчанию, чтобы удалить первую букву в полях, имя которых начинается с F. честно говоря, это кажется мне довольно странным.

это поведение можно настроить с помощью атрибутов. Например:

[JSONMarshalled(False)]
FFoo: Integer; 

[JSONMarshalled(True)]
[JSONName('Blah')]
Bar: Integer;

насколько я вижу, ничего из этого не правильно зарегистрированный.