Delphi 11.3 – 无法从变量创建/添加JSON。

huangapple go评论157阅读模式
英文:

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提到的,您可能无法避免更改所有的调用。

更新: 或者您可以为TJSONNumberTJSONObject创建类助手,并为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.

huangapple
  • 本文由 发表于 2023年6月13日 18:24:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/76463926.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定