Дельфы Отдыхают.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;
насколько я вижу, ничего из этого не правильно зарегистрированный.