【问题标题】:Delphi Dictionary Save/Load. TDictionary not serializable?Delphi 字典保存/加载。 TDictionary 不可序列化?
【发布时间】:2017-12-15 15:52:19
【问题描述】:

TDictionary : SaveToFile / LoadFromFile

多么优雅的解决方案! 首先,一切都按预期运行。

内容以看起来正确的 JSON 格式保存到文件中。 但是重新加载文件后,出现了问题:

Type
  TEnumCategTypes = ( e_SQL1, e_VBA, e_Text );
  TCategParams = class
    fontStyles  : TFontStyles;
    rgbColor    : COLORREF;
    end;

  TdictCategory = class ( TDictionary<TEnumCategTypes, TCategParams> )
    public
      public class function LoadFromFile( const AFileName: string ): TdictCategory;
      public class procedure SaveToFile( const AFileName: string; dict: TdictCategory );
    end;

implementation

class procedure TdictCategory.SaveToFile( const AFileName: string; dict: TdictCategory );
var
  stream : TStringStream;
begin
  try
    stream := TStringStream.Create( TJson.ObjectToJsonString( dict ) ) ;
    stream.SaveToFile( AFileName )
  finally
    stream.Free;
  end;
end;
//---
class function TdictCategory.LoadFromFile( const AFileName: string ): TdictCategory;
var
  stream: TStringStream;
begin
  stream   := TStringStream.Create;
  try
    stream.LoadFromFile( AFileName );
    result := TJson.JsonToObject<TdictCategory>( stream.DataString );
  finally
    stream.Free;
  end;
end;

测试如下。所有的荣耀都结束了。 这是代码,包括注释:

..
var
  cc: Colorref;
begin
  ..                                                          // fill values 
  cc := DictCategory.Items[ e_SQL1 ].rgbColor;                // Okay, it works
  TdictCategory.SaveToFile( 'category.json', DictCategory );  // Even the contents of the file, looks good 
  DictCategory.Clear;
  DictCategory.Free;
  DictCategory := nil;
  DictCategory := TdictCategory.LoadFromFile( 'category.json' );   // DictCategory is no longer NIL, and it looks optically well..
  cc           := DictCategory.Items[ e2_sql_aggregate ].rgbColor; // C R A S H !!!  with AV

看来Delphi(Berlin 10.1),不能序列化Dictionary!如果这是真的,那真的让我很伤心。我相信还有很多其他的。还是附上的代码有错误?

【问题讨论】:

  • 你的问题很冗长。归结为TJson.JsonToObject&lt;T&gt;(..)(也可能是TJson.ObjectToJsonObject&lt;T&gt;(..))不能与TList&lt;T&gt;TDictionary&lt;T&gt; 等泛型类一起正常工作。

标签: delphi serialization tdictionary


【解决方案1】:

TJson.JsonToObject 最终将使用其默认构造函数实例化对象(请参阅REST.JsonReflect.TJSONUnMarshal.ObjectInstance)。

现在查看System.Generics.Collections,您会发现TDictionary&lt;TKey,TValue&gt; 没有默认构造函数(不,RTTI 没有关于参数默认值的信息,因此不会考虑带有Capacity: Integer = 0 的构造函数)。

这意味着 RTTI 将进一步查找并找到 TObject.Create 并在字典类上调用它,这将为您留下一个半初始化对象(在没有运行您的代码的情况下,我猜它的 FComparer 没有被分配哪个构造函数TDictionary&lt;TKey,TValue&gt; 会做的)。

长话短说:向您的TdictCategory 添加一个无参数构造函数,然后在那里调用inherited Create;。然后TJSONUnMarshal.ObjectInstance 将找到无参数构造函数并调用所有必要的代码来正确初始化实例。

无论如何,您可能不会对结果感到满意,因为 REST.JsonReflect 只是序列化了实例的所有内部状态(除非通过未在 RTL 类中完成的属性明确排除)并因此反序列化它们,这意味着此类 JSON 仅与 Delphi-to-Delphi 兼容。

【讨论】:

  • 同意,默认构造函数可能是这个 AV 的原因。在没有运行单个测试的情况下,我只是怀疑FComparer 可能已被序列化和反序列化(作为 invalid 引用)。可惜 Delphi RTL 没有一些共同点,比如 [Serializable][NonSerializable] 的类和字段属性。
  • @StefanGlienke:TdictCategory 的无参数构造函数 - 已测试。测试正确完成,没有 AV 崩溃。但是对于每个 PAIR,VALUE 中的所有项目都是空的。最终测试前,基于try/fail方法,将原来的“TCategParams”声明改为:“TCategParams = class aFontStyles: Byte; rgbColor: COLORREF ; 结尾;”。关于 SaveToFile 部分中的 json 文本。 json文件的内容似乎是正确的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-22
  • 2013-01-02
  • 1970-01-01
  • 1970-01-01
  • 2020-02-26
相关资源
最近更新 更多