json – 为什么反序列化的TDictionary不能正常工作?

前端之家收集整理的这篇文章主要介绍了json – 为什么反序列化的TDictionary不能正常工作?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我尝试使用标准delphi序列化程序序列化/反序列化标准delphi容器.
  1. procedure TForm7.TestButtonClick(Sender: TObject);
  2. var
  3. dict: TDictionary<Integer,Integer>;
  4. jsonValue: TJSONValue;
  5. begin
  6. //serialization
  7. dict := TDictionary<Integer,Integer>.Create;
  8. dict.Add(1,1);
  9. jsonValue := TJsonConverter.ObjectToJSON(dict);
  10. dict.Free;
  11.  
  12. //deserialization
  13. dict := TJsonConverter.JSONToObject(jsonValue) as TDictionary<Integer,Integer>;
  14. try
  15. Assert(dict.ContainsKey(1),'deserialization error - key not found');
  16. except
  17. Assert(false,'deserialization error - dict object broken');
  18. end;
  19. end;

有一种方法我将对象转换为JSON,反之亦然;

  1. class function TJsonConverter.JSONToObject(AJSONValue: TJSONValue): TObject;
  2. var
  3. lUnMarshal: TJSONUnMarshal;
  4. begin
  5. lUnMarshal := TJSONUnMarshal.Create();
  6. try
  7. Result := lUnMarshal.Unmarshal(AJSONValue);
  8. finally
  9. lUnMarshal.Free;
  10. end;
  11. end;
  12.  
  13. class function TJsonConverter.ObjectToJSON(AData: TObject): TJSONValue;
  14. var
  15. lMarshal: TJSONMarshal;
  16. begin
  17. lMarshal := TJSONMarshal.Create();
  18.  
  19. try
  20. Result := lMarshal.Marshal(AData);
  21. finally
  22. lMarshal.Free;
  23. end;
  24. end;

线:

  1. dict := TJsonConverter.JSONToObject(jsonValue) as TDictionary<Integer,Integer>;

不能正确创建字典.
以下是构造函数创建dict的方式:
[

这是通过反序列化创建的dict:

我该如何解决

编辑:
这是JSON内容

  1. {
  2. "type" : "System.Generics.Collections.TDictionary<System.Integer,System.Integer>","id" : 1,"fields" : {
  3. "FItems" : [
  4. [ -1,0 ],[ -1,[ 911574339,1,1 ]
  5. ],"FCount" : 1,"FGrowThreshold" : 3,"FKeyCollection" : null,"FValueCollection" : null
  6. }
  7. }

解决方法

问题是TJSONMarshal使用RTTI实例化字典.它通过调用它可以找到的第一个无参数构造函数来实现.而且,遗憾的是,这是TObject中定义的构造函数.

让我们看一下在TDictionary< K,V>中声明的构造函数.它们至少在我的XE7版本中:

  1. constructor Create(ACapacity: Integer = 0); overload;
  2. constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
  3. constructor Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>); overload;
  4. constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>); overload;
  5. constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>;
  6. const AComparer: IEqualityComparer<TKey>); overload;

所有这些构造函数都有参数.

不要被你写的这个事实所迷惑

  1. TDictionary<Integer,Integer>.Create

并创建一个分配了FComparer的实例.这解决了上面的第一个重载,因此编译器将该代码重写为

  1. TDictionary<Integer,Integer>.Create(0)

填写默认参数.

您需要做的是确保您只使用具有正确实例化类的无参数构造函数的类.不幸的是TDictionary< K,V>不符合要求.

但是,您可以派生一个引入无参数构造函数的子类,并且您的代码应该与该类一起使用.

以下代码演示:

  1. {$APPTYPE CONSOLE}
  2.  
  3. uses
  4. System.SysUtils,System.Generics.Collections,System.Rtti;
  5.  
  6. type
  7. TDictionary<K,V> = class(System.Generics.Collections.TDictionary<K,V>)
  8. public
  9. constructor Create;
  10. end;
  11.  
  12. { TDictionary<K,V> }
  13.  
  14. constructor TDictionary<K,V>.Create;
  15. begin
  16. inherited Create(0);
  17. end;
  18.  
  19. type
  20. TInstance<T: class> = class
  21. class function Create: T; static;
  22. end;
  23.  
  24. class function TInstance<T>.Create: T;
  25. // mimic the way that your JSON marshalling code instantiates objects
  26. var
  27. ctx: TRttiContext;
  28. typ: TRttiType;
  29. mtd: TRttiMethod;
  30. cls: TClass;
  31. begin
  32. typ := ctx.GetType(TypeInfo(T));
  33. for mtd in typ.GetMethods do begin
  34. if mtd.HasExtendedInfo and mtd.IsConstructor then
  35. begin
  36. if Length(mtd.GetParameters) = 0 then
  37. begin
  38. cls := typ.AsInstance.MetaclassType;
  39. Result := mtd.Invoke(cls,[]).AsType<T>;
  40. exit;
  41. end;
  42. end;
  43. end;
  44. Result := nil;
  45. end;
  46.  
  47. var
  48. Dict: TDictionary<Integer,Integer>;
  49.  
  50. begin
  51. Dict := TInstance<TDictionary<Integer,Integer>>.Create;
  52. Dict.Add(0,0);
  53. Writeln(BoolToStr(Dict.ContainsKey(0),True));
  54. Readln;
  55. end.

猜你在找的JavaScript相关文章