英文:
Delphi 11.3 - Unable to create/Add JSONs from variant
问题
I am migrating some projects from Delphi 10.4 to Delphi 11.3.
I am facing some problems with the JSON library:
See the following codes:
First case:
function TestCreate;
var
LValue: Variant;
LJSON: TJSONNumber;
begin
LValue := 100;
LJSON := TJSONNumber.Create(LValue);
end;
Compiling this, it results in:
[dcc64 Error] _Unit.pas(74): E2251 Ambiguous overloaded call to 'Create'
System.JSON.pas(435): Related method: constructor TJSONNumber.Create(const string);
System.JSON.pas(439): Related method: constructor TJSONNumber.Create(const Double);
Second case:
function TestAddPair;
var
LValue: Variant;
LJSON: TJSONObject;
begin
LValue := 100;
LJSON := TJSONObject.Create();
LJSON.AddPair('Test', LValue);
end;
Compiling this, it results in:
[dcc64 Error] _Unit.pas(77): E2251 Ambiguous overloaded call to 'AddPair'
System.JSON.pas(661): Related method: function TJSONObject.AddPair(const string; const Boolean): TJSONObject;
System.JSON.pas(651): Related method: function TJSONObject.AddPair(const string; const Double): TJSONObject;
System.JSON.pas(636): Related method: function TJSONObject.AddPair(const string; const string): TJSONObject;
Both used to work properly on Delphi 10.4, but on Delphi 11.3 they do not compile.
Is there a way to let them compile? I'd prefer not to modify each command that uses a Variant to create/add a JSON.
英文:
I am migrating some projects from Delphi 10.4 to Delphi 11.3.
I am facing some problems with the JSON library:
See the following codes:
First case:
function TestCreate;
var
LValue: Variant;
LJSON: TJSONNumber;
begin
LValue := 100;
LJSON := TJSONNumber.Create(LValue);
end;
Compiling this, it results in:
[dcc64 Error] _Unit.pas(74): E2251 Ambiguous overloaded call to 'Create'
System.JSON.pas(435): Related method: constructor TJSONNumber.Create(const string);
System.JSON.pas(439): Related method: constructor TJSONNumber.Create(const Double);
Second case:
function TestAddPair;
var
LValue: Variant;
LJSON: TJSONObject;
begin
LValue := 100;
LJSON := TJSONObject.Create();
LJSON.AddPair('Test', LValue);
end;
Compiling this, it results in:
[dcc64 Error] _Unit.pas(77): E2251 Ambiguous overloaded call to 'AddPair'
System.JSON.pas(661): Related method: function TJSONObject.AddPair(const string; const Boolean): TJSONObject;
System.JSON.pas(651): Related method: function TJSONObject.AddPair(const string; const Double): TJSONObject;
System.JSON.pas(636): Related method: function TJSONObject.AddPair(const string; const string): TJSONObject;
Both used to work properly on Delphi 10.4, but on Delphi 11.3 they do not compile.
Is there a way to let them compile? I'd prefer not to modify each command that uses a Variant to create/add a JSON.
答案1
得分: 3
A Variant can implicitly convert to both string or Double type without any preference for one of them.
在R104中,接受字符串参数的构造函数是受保护的,而在11.3中是公共的。
正如Toon提到的,您可能无法避免更改所有的调用。
更新: 或者您可以为TJSONNumber
和TJSONObject
创建类助手,并为Variant添加重载。例如:
type
TJSONNumberHelper = class helper for TJSONNumber
public
constructor Create(const AValue: Variant); overload;
end;
constructor TJsonNumberHelper.Create(const AValue: Variant);
begin
inherited Create(Double(AValue));
end;
英文:
A Variant can implicitly convert to both string or Double type without any preference for one of them.
In R104 the constructor taking a string parameter is protected, while in 11.3 it is public.
As Toon mentioned, you may not be able to avoid changing all the calls.
Update: Alternatively you can create class helpers for TJSONNumber
and TJSONObject
with overrides for Variant. F.i. like this:
type
TJSONNumberHelper = class helper for TJSONNumber
public
constructor Create(const AValue: Variant); overload;
end;
constructor TJsonNumberHelper.Create(const AValue: Variant);
begin
inherited Create(Double(AValue));
end;
答案2
得分: 1
这是我的将Variant转换为JSON的函数。
它会识别Variant是否包含Null、Number、String、Bool或Date,并返回相应的JSONValue。它还会检查Variant是否是一个数组,如果是的话,将返回其值的TJSONArray。
function VariantToJSON(Value: Variant): TJSONValue;
var
i: integer;
JSONArray: TJSONArray;
function VarToInt(Value: Variant): integer;
begin
Result := Value;
end;
function VarToFloat(Value: Variant): double;
begin
Result := Value;
end;
function Item(Value: Variant): TJSONValue;
begin
case VarType(Value) of
varEmpty, varNull, varUnknown:
Result := TJSONNull.Create;
varSmallint, varInteger, varShortInt, VarInt64:
Result := TJSONNumber.Create(VarToInt(Value));
varSingle, varDouble, varCurrency:
Result := TJSONNumber.Create(VarToFloat(Value));
varDate:
Result := TJSONString.Create(DateToISO8601(Value));
varBoolean:
Result := TJSONBool.Create(Value);
else
Result := TJSONString.Create(Value);
end;
end;
begin
if not VarIsArray(Value) then
begin
Result := Item(Value);
end
else
begin
JSONArray := TJSONArray.Create;
for i := 0 to Length(Value) - 1 do
begin
JSONArray.AddElement(Item(Value[i]));
end;
Result := JSONArray;
end;
end;
注意:我已经修正了一些错误,包括数组索引的问题(从0开始)和数组长度的计算。
英文:
This is my function to convert from Variant to JSON.
It identifies if the Variant contains a Null, Number, String, Bool or Date, returning the corresponding JSONValue, it also checks if the Variant is an array so it returns its values in a TJSONArray.
function VariantToJSON(Value: Variant): TJSONValue;
var i: integer;
JSONArray: TJSONArray;
function VarToInt(Value: Variant): integer;
begin
Result := Value;
end;
function VarToFloat(Value: Variant): double;
begin
Result := Value;
end;
function Item(Value: Variant): TJSONValue;
begin
case VarType(Value) of
varEmpty, varNull, varUnknown:
Result := TJSONNull.Create;
varSmallint, varInteger, varShortInt, VarInt64:
Result := TJSONNumber.Create(VarToInt(Value));
varSingle, varDouble, varCurrency:
Result := TJSONNumber.Create(VarToFloat(Value));
varDate:
Result := TJSONString.Create(DateToISO8601(Value));
varBoolean:
Result := TJSONBool.Create(Value);
else
Result := TJSONString.Create(Value);
end;
end;
begin
if not VarIsArray(Value) then
begin
Result := Item(Value);
end
else
begin
JSONArray := TJSONArray.Create;
for i := 0 to Length(Value) do
begin
JSONArray.AddElement(Item(Value[i]));
end;
Result := JSONArray;
end;
end;
答案3
得分: 0
Another alternative and different approach could be using mORMot, furthermore it's very optimized to use as little memory and very fast JSON serialization / un-serialization.
program Project1;
{$APPTYPE CONSOLE}
uses
Syncommons;
var
DoubleNumber : Double;
VariantNumber : Variant;
Json : variant;
begin
DoubleNumber := 100;
VariantNumber := 101;
Json := _Obj(['Double' , DoubleNumber ,
'Variant' , VariantNumber
]);
assert(VariantSaveJson(Json)='{"Double":100,"Variant":101}');
end.
英文:
Another alternative and different approach could be using mORMot, furthermore it's very optimized to use as little memory and very fast JSON serialization / un-serialization.
program Project1;
{$APPTYPE CONSOLE}
uses
Syncommons;
var
DoubleNumber : Double;
VariantNumber : Variant;
Json : variant;
begin
DoubleNumber := 100;
VariantNumber := 101;
Json := _Obj(['Double' , DoubleNumber ,
'Variant' , VariantNumber
]);
assert(VariantSaveJson(Json)='{"Double":100,"Variant":101}');
end.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论