1

I am trying to serialize this dictionary:

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 });

After that I get a wrong result string json, like this:

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

But it should be something like this:

{
  "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,
        },
      }
    }
  }
}

The classes are:

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;
}

and ResetableBaseObject is just a base class containing a common method. I had already using this approach for another stuff where instead of type ResetableBaseObject, were used an enumeration and the serialization/deserialization worked perfectly. The reason for using a dictionary is that this way I can dynamically set values according to some UI theme:

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

Why is System.Text.Json.JsonSerializer.Serialize/Deserialize not able to do the job for nested non-enum types?

dbc
  • 104,963
  • 20
  • 228
  • 340
IamJose
  • 81
  • 8
  • `System.Text.Json` does not serialize properties of derived classes. This is the documented behavior, see [Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?](https://stackoverflow.com/a/62033671/3744182). If you want to serialize and deserialize a class hierarchy you will need to create a custom converter, see [Is polymorphic deserialization possible in System.Text.Json?](https://stackoverflow.com/q/58074304/3744182). In fact I think this is a duplicate of those two, agree? – dbc Apr 29 '21 at 13:50
  • 1
    Alternatively you could eliminate the requirement to serialize and deserialize class hierarchies by declaring declare `public class ResetableObjectTheme { public PatternObject ResetablePatternObject { get; set; } public MaterialObject ResetableMaterialObject { get; set; } }` – dbc Apr 29 '21 at 13:52
  • @dbc yes, you are right. Just modified the property types. Thx. – IamJose Apr 29 '21 at 13:57

1 Answers1

2

You are using polymorphism for the properties of ResetableObjectTheme, and System.Text.Json does not support polymorphism by default. From the docs:

Serialization of a polymorphic type hierarchy is not supported. For example, if a property is defined as an interface or an abstract class, only the properties defined on the interface or abstract class are serialized, even if the runtime type has additional properties.
The exceptions to this behavior are explained in this section...

The simplest way around the limitation is to declare the properties of ResetableObjectTheme to be the appropriate derived type:

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

If you actually need to serialize and deserialize polymorphic subtypes, you will need to create a custom JsonConverter as shown in e.g. Is polymorphic deserialization possible in System.Text.Json?.

dbc
  • 104,963
  • 20
  • 228
  • 340