如何使用 System.Text.Json 序列化/反序列化非枚举类型的嵌套字典?

Posted

技术标签:

【中文标题】如何使用 System.Text.Json 序列化/反序列化非枚举类型的嵌套字典?【英文标题】:How to Serialize/deserialize a nested dictionary of non-enum types with System.Text.Json? 【发布时间】:2021-07-22 15:31:03 【问题描述】:

我正在尝试序列化这本字典:

IDictionary<string, ResetableObjectTheme> ResetableObjectThemes = new Dictionary<string, ResetableObjectTheme>()

    "ThemeDark", new ResetableObjectTheme()  ResetablePatternObject = new PatternObject(), ResetableMaterialObject = new MaterialObject(),
    "ThemeLight", new ResetableObjectTheme()  ResetablePatternObject = new PatternObject(), ResetableMaterialObject = new MaterialObject(),
;

string json = System.Text.Json.JsonSerializer.Serialize(ResetableObjectThemes, new JsonSerializerOptions()  WriteIndented = true );

之后我得到一个错误的结果字符串 json,像这样:


  "ResetableObjectThemes": 
    "ThemeDark": 
      "ResetablePatternObject": ,
      "ResetableMaterialObject": 
    ,
    "ThemeLight": 
      "ResetablePatternObject": ,
      "ResetableMaterialObject": 
    
  

但它应该是这样的:


  "ResetableObjectThemes": 
    "ThemeDark": 
      "ResetablePatternObject": 
        "Thickness": 3,
        "BoundaryColor": 
          "ColorContext": null,
          "A": 255,
          "R": 0,
          "G": 0,
          "B": 128,
        ,
      ,
      "ResetableMaterialObject": 
        "BoundaryThickness": 3,
        "BoundaryColor": 
          "ColorContext": null,
          "A": 255,
          "R": 0,
          "G": 0,
          "B": 255,       
        ,
      
    ,
    "ThemeLight": 
      "ResetablePatternObject": 
        "Thickness": 3,
        "BoundaryColor": 
          "ColorContext": null,
          "A": 255,
          "R": 0,
          "G": 0,
          "B": 128,
        ,
      ,
      "ResetableMaterialObject": 
        "BoundaryThickness": 3,
        "BoundaryColor": 
          "ColorContext": null,
          "A": 255,
          "R": 0,
          "G": 0,
          "B": 255,
        ,
      
    
  

类是:

public class ResetableObjectTheme

    public ResetableBaseObject ResetablePatternObject  get; set;  = new PatternObject();
    public ResetableBaseObject ResetableMaterialObject  get; set;  = new MaterialObject();


public class PatternObject : ResetableBaseObject

    public double Thickness  get; set;  = 1;
    public Color BoundaryColor  get; set;  = Colors.Blue;

public class MaterialObject : ResetableBaseObject

    public double BoundaryThickness  get; set;  = 3;
    public Color BoundaryColor  get; set;  = Colors.Blue;

ResetableBaseObject 只是一个包含通用方法的基类。 我已经将这种方法用于另一个东西,而不是类型 ResetableBaseObject,而是使用枚举并且序列化/反序列化工作得很好。 使用字典的原因是这样我可以根据一些 UI 主题动态设置值:

ResetableObjectThemes[ThemeManager.CurrentTheme].ResetablePatternObject = new PatternObject()  Thickness = 5.5 ;

为什么 System.Text.Json.JsonSerializer.Serialize/Deserialize 不能为嵌套的非枚举类型完成这项工作?

【问题讨论】:

System.Text.Json 不序列化派生类的属性。这是记录在案的行为,请参阅Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?。如果要序列化和反序列化类层次结构,则需要创建自定义转换器,请参阅Is polymorphic deserialization possible in System.Text.Json?。事实上,我认为这是两者的重复,同意吗? 另外,您可以通过声明 declare public class ResetableObjectTheme public PatternObject ResetablePatternObject get; set; public MaterialObject ResetableMaterialObject get; set; 来消除序列化和反序列化类层次结构的要求 @dbc 是的,你是对的。只是修改了属性类型。谢谢。 【参考方案1】:

您正在为ResetableObjectTheme 的属性使用多态,而System.Text.Json 默认不支持多态。来自docs:

不支持多态类型层次结构的序列化。例如,如果一个属性被定义为接口或抽象类,那么即使运行时类型有附加属性,也只会序列化接口或抽象类上定义的属性。 本节说明了此行为的例外情况...

绕过限制的最简单方法是将ResetableObjectTheme 的属性声明为适当的派生类型:

public class ResetableObjectTheme 
 
    public PatternObject ResetablePatternObject  get; set;  
    public MaterialObject ResetableMaterialObject  get; set;  

如果您确实需要序列化和反序列化多态子类型,您将需要创建一个custom JsonConverter,如示例所示。 Is polymorphic deserialization possible in System.Text.Json?.

【讨论】:

以上是关于如何使用 System.Text.Json 序列化/反序列化非枚举类型的嵌套字典?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 System.Text.Json 序列化/反序列化非枚举类型的嵌套字典?

如何让 System.Text.Json 将对象反序列化为其原始类型?

缺少属性时如何强制 System.Text.Json 序列化程序抛出异常?

如何将类字段与 System.Text.Json.JsonSerializer 一起使用?

如何反序列化作为 System.Text.Json 中的字符串的嵌套 JSON 对象?

如何使用 System.Text.Json 将 json 字符串或流反序列化到 Dictionary<string,string>