-1

I have an array of objects which I want to write to a json file and recover it later Point - Visual Basic class:

<Serializable> Public Class Point
    Implements IComparable
    Public Property X As Integer
    Public Property Y As Integer
    Public Sub New()
        X = 0
        Y = 0
    End Sub
    Public Sub New(ByVal x As Integer, ByVal y As Integer)
        Me.X = x
        Me.Y = y
    End Sub
End Class

Point3D - C# class

    [Serializable]
    public class Point3D : Point
    {
        public int Z { get; set; }
        public Point3D() : base()
        {
            var rnd = new Random();
            Z = rnd.Next(10);
        }
        public Point3D(int x, int y, int z) : base(x, y) 
        { 

            this.Z = z; 
        }
    }

Serialization works fine but when I try to deserialize json from file, all objects presented as Point3D (even the ones with only X and Y variables). Before deserialization: enter image description here After: enter image description here

Serialization code block:

            using (var fs = new FileStream(dlg.FileName, FileMode.Create, FileAccess.Write))
            {
                switch (Path.GetExtension(dlg.FileName))
                {
                    ...
                    case ".json":
                        var jf = new JsonSerializer();
                        jf.TypeNameHandling= TypeNameHandling.Auto;
                        using (var w = new StreamWriter(fs))
                            jf.Serialize(w, points);
                        break;
                }
            }

Deserialization code block:

            using (var fs = new FileStream(dlg.FileName, FileMode.Open, FileAccess.Read))
            {
                switch (Path.GetExtension(dlg.FileName))
                {
                    ...
                    case ".json":
                        var jf = new JsonSerializer();
                        using (var r = new StreamReader(fs))
                            points = (Point[])jf.Deserialize(r, typeof(Point3D[]));
                        break;
                }
            }

Code I use to initialize array of objects (Point and Point3D):

        private void buttonCreate_Click(object sender, EventArgs e)
        {
            points = new Point[5];
            var rnd = new Random();
            for (int i = 0; i < points.Length; i++)
            {
                points[i] = rnd.Next(3) % 2 == 0 ? new Point() : new Point3D();
            }
            listBox.DataSource = points;
        }

And json string

{"$type":"PointLib.Point[], PointLib","$values":[{"$type":"LabOneFormsApp.Point3D, LabOneFormsApp","Z":6,"X":0,"Y":0},{"$type":"LabOneFormsApp.Point3D, LabOneFormsApp","Z":1,"X":0,"Y":0},{"$type":"PointLib.Point, PointLib","X":0,"Y":0},{"$type":"PointLib.Point, PointLib","X":0,"Y":0},{"$type":"PointLib.Point, PointLib","X":0,"Y":0}]}

I tried adding

jf.TypeNameHandling= TypeNameHandling.Auto;

to my code but it does not seem to work for me. Any ideas?

Rearden
  • 1
  • 2
  • 1
    You said with `typeof(Point3D[])` when deserializing you want that type back and so the jsonserializer gave you such a type back. What if you just leave that part away? – Ralf Feb 07 '23 at 15:33
  • I tried `points = (Point[])jf.Deserialize(r);` and it gave me an [error](https://learn.microsoft.com/en-us/dotnet/csharp/misc/cs1503?f1url=%3FappId%3Droslyn%26k%3Dk(CS1503)). I also tried `points = (Point[])jf.Deserialize(r, typeof(Point[]));` and it returned array full of points with only 2 arguments (as expected) :( – Rearden Feb 07 '23 at 16:07
  • 1
    We need some code for testing. You have to remove all images , thet are useless, and post the code you use to create your point object and Json string you are trying to deserialize – Serge Feb 07 '23 at 16:14
  • Hey Serge! I updated the question. Full project can be found [here](https://github.com/Krearden/ComponentProgramming/tree/main/LR1/Lab) – Rearden Feb 07 '23 at 16:24
  • Welcome to Stack Overflow! You might be able to achieve this by creating your own `JsonConverter` implementation, something a bit like this answer maybe: https://stackoverflow.com/a/46175763/16563198 – sbridewell Feb 07 '23 at 17:46
  • If you don't want to use `TypeNameHandling`, [Deserializing polymorphic json classes without type information using json.net](https://stackoverflow.com/q/19307752/3744182). might be helpful for you. You write a `JsonConverter` that could detect whether you are deserializing `Point` or `Point3D` based on the presence of the `Z` property. – dbc Feb 09 '23 at 19:23

1 Answers1

0

I've decided to do it simple way

case ".json":
                    var reader = new StreamReader(fs).ReadToEnd();
                    var jsonFile = JsonConvert.DeserializeObject<List<Dictionary<string, int>>>(reader);

                    if (jsonFile != null)
                    {
                        points = new Point[jsonFile.Count];

                        for (int i = 0; i < jsonFile.Count; i++)
                        {
                            var pointDict = jsonFile[i];

                            switch (pointDict.Count)
                            {
                                case 2:
                                    points[i] = new Point(pointDict["X"], pointDict["Y"]);
                                    break;

                                case 3:
                                    points[i] = new Point3D(pointDict["X"], pointDict["Y"], pointDict["Z"]);
                                    break;
                            }
                        }
                    }
                    else
                    {
                        points = null;
                    }

Thanks everyone for the answers!

Rearden
  • 1
  • 2