-1

I have the following code

using System;
using System.Collections.Generic;
using System.Text.Json;
public class Program
{
    public static void Main()
    {
        Console.WriteLine("Hello World");
        
        var shapes = new List<Shape>();
        shapes.Add(new Circle { Name = "Circle1", Diameter = 2.0});
        shapes.Add(new Circle { Name = "Circle2", Diameter = 2.0});
        
        shapes.Add(new Rectangle { Name = "Rect1", Length = 2.0});
        shapes.Add(new Rectangle { Name = "Rect2", Length = 2.0});
        
        var serialized = JsonSerializer.Serialize(shapes);
        Console.WriteLine(serialized);
    }
    
    
    public abstract class Shape
    {
        public string Name { get;set;}
    }
    
    public class Circle:Shape
    {
        public double Diameter { get;set;}
    }
    public class Rectangle:Shape
    {
        public double Length {get;set;}
    }   
    
}

When serializing, i am losing properties of rectangle and circle, only getting the ones from Shape.

This is the outpout

[{"Name":"Circle1"},{"Name":"Circle2"},{"Name":"Rect1"},{"Name":"Rect2"}]

Which is expected, given that the serializer thinks they are all "Shape", how can i make it so that its smart enough to serialize to proper sub classes

dbc
  • 104,963
  • 20
  • 228
  • 340
Zoinky
  • 4,083
  • 11
  • 40
  • 78
  • Are you going to use Text.Json onlly or open to Newtonsoft.Json? – Serge Jan 12 '22 at 19:52
  • hoping to stick to Text.Json if possible, – Zoinky Jan 12 '22 at 19:55
  • 1
    if you want to stick with Text.Json look at https://stackoverflow.com/questions/58074304/is-polymorphic-deserialization-possible-in-system-text-json . Newtonsoft makes it much easier. – Serge Jan 12 '22 at 19:57
  • But the main problem is to deserialize from json – Serge Jan 12 '22 at 20:06
  • System.Text.Json only serializes the properties of the **declared** type - here `Shape` - rather than the actual, concrete type - here `Circle` and `Rectangle`. See [Why does System.Text Json Serialiser not serialise this generic property but Json.NET does?](https://stackoverflow.com/a/62033671/3744182). If you only need to serialize, you could serialize a `List` rather than a `List` and the actual concrete type will be serialized. But if you need to deserialize, see [Is polymorphic deserialization possible in System.Text.Json?](https://stackoverflow.com/q/58074304/3744182). – dbc Jan 29 '22 at 21:49
  • Do those two questions answer yours also? – dbc Jan 29 '22 at 21:49

1 Answers1

0

you can make your code much more simple if changes your base class

public abstract class Shape
{
    public string Name
    {
        get { return this.GetType().Name; }
    }
}

in this case you can initiate objects more simple and safe way. Also I recommend to use Newtonsoft.Json. It will make your life much easier

    var origShapes = new List<Shape>();

    origShapes.Add(new Circle {  Diameter = 2.0 });
    origShapes.Add(new Circle { Diameter = 2.0 });
    origShapes.Add(new Rectangle {  Length = 2.0 });
    origShapes.Add(new Rectangle { Length = 2.0 });

    var json = JsonConvert.SerializeObject(origShapes, Newtonsoft.Json.Formatting.Indented);

result

[
  {
    "Diameter": 2.0,
    "Name": "Circle"
  },
  {
    "Diameter": 2.0,
    "Name": "Circle"
  },
  {
    "Length": 2.0,
    "Name": "Rectangle"
  },
  {
    "Length": 2.0,
    "Name": "Rectangle"
  }
]

test

    List<Shape> shapesBack = JArray.Parse(json)
         .Select(o => (Shape)JsonConvert
        .DeserializeObject(o.ToString(), Type.GetType((string)o["Name"]))).ToList();

    foreach (var shape in shapesBack)
    {
        Console.WriteLine(shape.GetType().Name);
    }

test result

Circle
Circle
Rectangle
Rectangle
Serge
  • 40,935
  • 4
  • 18
  • 45