Delphi Rest.JSON JsonToObject仅适用于f变量 [英] Delphi Rest.JSON JsonToObject only works with f variables
问题描述
我只是看着 REST.Json ObjectToJsonString()
和 JsonToObject()
调用。
主要尝试这样做:
我注意到,当他们开始使用 F
字符时,我只能使变量工作。我找不到任何文档。这是预期的行为吗?在开始的时候,我是否应该使用$ code> F 命名所有类的变量?如果是的,有人可以解释为什么吗?
我创建了一个类 TTestJSON
并定义了两个成员变量并将其设置为'WORKS'和'FAILS'。
然后我从对象创建了一个JSON字符串值:
{
varThatWorksBeacuseItStartsWithF:WORKS,
sVarThatFailsBecauseItStartsWithS:FAILS
}
当从JSON字符串返回到对象时,只有 fVarThatWorksBeacuseItStartsWithF
变量正在正确复位在下面的代码中,使用上述JSON, test:= TJson.JsonToObject< TTestJSON>(JsonStr);
注意到 sVarThatFailsBecauseItStartsWithS
是而不是
失败
。
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;
结束
m1.Lines.Add('** JSONStr Value START **'+#13#10 + JsonStr +'** JSONStr Value END **'+#13#10);
test:= TJson.JsonToObject< TTestJSON>(JsonStr);
try
m1.Lines.Add('** Obj从JSON String开始**'+#13#10 + TJson.ObjectToJsonString(test)+#13#10 +'** Obj加载from JSON String End **');
finally
test.Free;
结束
结束
从结果中,以 f $ c $开头的var c>将
f
从JSON字符串中删除,而以 s
开头的那个仍然存在。我预计第二个结果将如下所示:
{
varThatWorksBeacuseItStartsWithF:WORKS,
sVarThatFailsBecauseItStartsWithS:FAILS
}
这是完整的代码,只需要一个按钮和vcl表单上的备忘录 - 也使用REST.Json:
unit Main;
接口
使用
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;
结束
TForm3 = class(TForm)
btn1:TButton;
m1:TMemo;
procedure btn1Click(Sender:TObject);
private
{私人声明}
public
{公开声明}
end;
var
Form3:TForm3;
执行
{$ R * .dfm}
程序TForm3.btn1Click(发件人: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;
结束
m1.Lines.Add('** JSONStr Value START **'+#13#10 + JsonStr +'** JSONStr Value END **'+#13#10);
test:= TJson.JsonToObject< TTestJSON>(JsonStr);
try
m1.Lines.Add('** Obj从JSON String开始**'+#13#10 + TJson.ObjectToJsonString(test)+#13#10 +'** Obj加载from JSON String End **');
finally
test.Free;
结束
结束
结束。
在Delphi中的JSON序列化是基于字段而不是属性。但大多数Delphi类都有友好的属性和F前缀字段。同时似乎Emb试图在生成的JSON中避免使用F前缀的名字。当序列化字段时,它们从名称中切断第一个F,并在从JSON读取时将其添加回(找到正确的字段)。看起来在Delphi中使用JSON序列化的唯一(安全)方法是将所有字段名称保留为前缀F(对于要序列化的字段):
TTestJSON = class
protected
FName:String;
public
属性名称:String读取FName写入FName;
结束
更新2:正如David所提到的,我们可以使用属性,然后我们有更好的控制:
使用
REST.Json.Types,//没有这个单元我们得到警告:W1025不支持的语言功能:'自定义属性'
REST.Json;
type
//所有记录字段都是序列化的,这里没有控制。
TRec = record
RecStr:String;
结束
//默认情况下,类的所有字段都是序列化的,但只有F前缀被正确序列化。
//我们可以使用JSONMarshalled属性来启用/禁用序列化。
//我们可以使用JSonName属性在JSON中将具有特定名称的字段序列化。
TTestJSON = class
[JSONMarshalled(True)] [JSonName('RecField')]
R:TRec;
结束
procedure TForm28.FormCreate(Sender:TObject);
var
测试:TTestJSON;
JsonStr:string;
begin
测试:= TTestJSON.Create;
try
Test.R.RecStr:='Some str';
JsonStr:= TJson.ObjectToJsonString(Test);
finally
FreeAndNil(Test);
结束
// JsonStr:{RecField:[Some str]}
测试:= TJson.JsonToObject< TTestJSON>(JsonStr);
FreeAndNil(Test);
结束
I'm using Delphi XE8.
I was just looking at the REST.Json ObjectToJsonString()
and JsonToObject()
calls.
Mainly attempting to do something like this:
How to convert an object to JSON and back with a single line of code
I noticed that I could only get variables to work when they started with an F
character. I couldn't find any documentation on this. Is this expected behavior? Should I be naming all variables inside of my classes with an F
at the start? If Yes, can someone explain why?
I created a class TTestJSON
and defined two member variables and set them to 'WORKS' and 'FAILS'.
Then I created a JSON string value from the object:
{
"varThatWorksBeacuseItStartsWithF":"WORKS",
"sVarThatFailsBecauseItStartsWithS":"FAILS"
}
When going back from a JSON string to object, only the fVarThatWorksBeacuseItStartsWithF
variable is being reset correctly. In the code below, test := TJson.JsonToObject<TTestJSON>(JsonStr);
using the above JSON, notice that the sVarThatFailsBecauseItStartsWithS
is ""
and not "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;
From the results, the var that starts with f
has the f
stripped out of the JSON string, and the one that starts with s
still has it in there. I would have expected that the second result would have looked like this:
{
"varThatWorksBeacuseItStartsWithF":"WORKS",
"sVarThatFailsBecauseItStartsWithS":"FAILS"
}
Here is the full code to reproduce - just has a button and a memo on a vcl form - also uses 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.
JSON serialization in Delphi is based on fields, not properties. But most of Delphi classes have friendly properties and F-prefixed fields. At same time seems Emb is trying to avoid of F-prefixed names in generated JSON. They cut off first "F" from name when serialize fields and add it back (to find correct field) when read from JSON. Seems the only (safe) way to use JSON serialization in Delphi is to keep all field names with prefix "F" (for the fields that you want to serialize):
TTestJSON = class
protected
FName: String;
public
property Name: String read FName write FName;
end;
UPDATE2: As David mentions, we can use attributes and then we have much better control:
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;
这篇关于Delphi Rest.JSON JsonToObject仅适用于f变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!