我尝试使用标准delphi序列化程序序列化/反序列化标准delphi容器.
- procedure TForm7.TestButtonClick(Sender: TObject);
- var
- dict: TDictionary<Integer,Integer>;
- jsonValue: TJSONValue;
- begin
- //serialization
- dict := TDictionary<Integer,Integer>.Create;
- dict.Add(1,1);
- jsonValue := TJsonConverter.ObjectToJSON(dict);
- dict.Free;
- //deserialization
- dict := TJsonConverter.JSONToObject(jsonValue) as TDictionary<Integer,Integer>;
- try
- Assert(dict.ContainsKey(1),'deserialization error - key not found');
- except
- Assert(false,'deserialization error - dict object broken');
- end;
- end;
有一种方法我将对象转换为JSON,反之亦然;
- class function TJsonConverter.JSONToObject(AJSONValue: TJSONValue): TObject;
- var
- lUnMarshal: TJSONUnMarshal;
- begin
- lUnMarshal := TJSONUnMarshal.Create();
- try
- Result := lUnMarshal.Unmarshal(AJSONValue);
- finally
- lUnMarshal.Free;
- end;
- end;
- class function TJsonConverter.ObjectToJSON(AData: TObject): TJSONValue;
- var
- lMarshal: TJSONMarshal;
- begin
- lMarshal := TJSONMarshal.Create();
- try
- Result := lMarshal.Marshal(AData);
- finally
- lMarshal.Free;
- end;
- end;
线:
- dict := TJsonConverter.JSONToObject(jsonValue) as TDictionary<Integer,Integer>;
不能正确创建字典.
以下是构造函数创建dict的方式:
[
我该如何解决?
编辑:
这是JSON内容
- {
- "type" : "System.Generics.Collections.TDictionary<System.Integer,System.Integer>","id" : 1,"fields" : {
- "FItems" : [
- [ -1,0 ],[ -1,[ 911574339,1,1 ]
- ],"FCount" : 1,"FGrowThreshold" : 3,"FKeyCollection" : null,"FValueCollection" : null
- }
- }
解决方法
问题是TJSONMarshal使用RTTI实例化字典.它通过调用它可以找到的第一个无参数构造函数来实现.而且,遗憾的是,这是TObject中定义的构造函数.
让我们看一下在TDictionary< K,V>中声明的构造函数.它们至少在我的XE7版本中:
- constructor Create(ACapacity: Integer = 0); overload;
- constructor Create(const AComparer: IEqualityComparer<TKey>); overload;
- constructor Create(ACapacity: Integer; const AComparer: IEqualityComparer<TKey>); overload;
- constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>); overload;
- constructor Create(const Collection: TEnumerable<TPair<TKey,TValue>>;
- const AComparer: IEqualityComparer<TKey>); overload;
所有这些构造函数都有参数.
不要被你写的这个事实所迷惑
- TDictionary<Integer,Integer>.Create
并创建一个分配了FComparer的实例.这解决了上面的第一个重载,因此编译器将该代码重写为
- TDictionary<Integer,Integer>.Create(0)
填写默认参数.
您需要做的是确保您只使用具有正确实例化类的无参数构造函数的类.不幸的是TDictionary< K,V>不符合要求.
但是,您可以派生一个引入无参数构造函数的子类,并且您的代码应该与该类一起使用.
以下代码演示:
- {$APPTYPE CONSOLE}
- uses
- System.SysUtils,System.Generics.Collections,System.Rtti;
- type
- TDictionary<K,V> = class(System.Generics.Collections.TDictionary<K,V>)
- public
- constructor Create;
- end;
- { TDictionary<K,V> }
- constructor TDictionary<K,V>.Create;
- begin
- inherited Create(0);
- end;
- type
- TInstance<T: class> = class
- class function Create: T; static;
- end;
- class function TInstance<T>.Create: T;
- // mimic the way that your JSON marshalling code instantiates objects
- var
- ctx: TRttiContext;
- typ: TRttiType;
- mtd: TRttiMethod;
- cls: TClass;
- begin
- typ := ctx.GetType(TypeInfo(T));
- for mtd in typ.GetMethods do begin
- if mtd.HasExtendedInfo and mtd.IsConstructor then
- begin
- if Length(mtd.GetParameters) = 0 then
- begin
- cls := typ.AsInstance.MetaclassType;
- Result := mtd.Invoke(cls,[]).AsType<T>;
- exit;
- end;
- end;
- end;
- Result := nil;
- end;
- var
- Dict: TDictionary<Integer,Integer>;
- begin
- Dict := TInstance<TDictionary<Integer,Integer>>.Create;
- Dict.Add(0,0);
- Writeln(BoolToStr(Dict.ContainsKey(0),True));
- Readln;
- end.