Serialize in one assembly, and de-serialize in another?

核能气质少年 提交于 2019-12-01 22:50:21

Yes, it is absolutely possible to serialize using classes in one assembly and deserialize into classes of another assembly using Json.Net. In fact, that is one of the main use cases for serialization in the first place -- transmitting data between different systems.

There are two things you need to keep in mind:

  1. If your source and target assemblies are different, then you should not include the actual fully-qualified type names as metadata in the JSON. In other words, make sure that the TypeNameHandling setting is set to None (which I believe is the default). If you include the type name metadata, then Json.Net will expect to find those assemblies on the receiving side, and the deserialization will fail because those assemblies are not there.
  2. If you are using interfaces in your class structure instead of concrete types then you will need to create one or more JsonConverter classes to handle the deserialization. When Json.Net sees an interface it will not know what type of concrete class to create, because it could be anything. A converter can look for other data that might be present in the JSON and tell Json.Net which concrete class to instantiate. If there is no obvious piece of data in the JSON that can be used as an indicator for the type, you can use a converter on the serialization side to add a custom indicator.

Here is some example code to demonstrate the concepts I've laid out. The demo is broken into two parts. The first part is the "sender", which serializes a made-up "diagram" class structure to JSON and writes it to a file. The second part is the "receiver", which reads the file and deserializes the JSON into a different set of classes. You'll notice I've intentionally made some of the class names in the receiver different than the sender, but they have the same property names and structure, so it still works. You'll also notice that the receiver program uses a custom JsonConverter to handle creating the correct IFigure instances using the presence of certain properties in the JSON as indicators.

Sender

using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;

namespace Sender
{
    class Program
    {
        static void Main(string[] args)
        {
            Diagram diagram = new Diagram
            {
                Title = "Flowchart",
                Shapes = new List<IShape>
                {
                    new Circle 
                    { 
                        Id = 1, 
                        Text = "Foo", 
                        Center = new Point { X = 1, Y = 5 }, 
                        Radius = 1.25 
                    },
                    new Line 
                    {
                        Id = 2,
                        A = new Point { X = 2.25, Y = 5 }, 
                        B = new Point { X = 4, Y = 5 } 
                    },
                    new Rectangle
                    {
                        Id = 3,
                        Text = "Bar",
                        TopLeft = new Point { X = 4, Y = 6.5 }, 
                        BottomRight = new Point { X = 8.5, Y = 3.5 } 
                    }
                }
            };

            string json = JsonConvert.SerializeObject(diagram, Formatting.Indented);

            File.WriteAllText(@"C:\temp\test.json", json);
        }
    }

    class Diagram
    {
        public string Title { get; set; }
        public List<IShape> Shapes { get; set; }
    }

    interface IShape
    {
        int Id { get; set; }
        string Text { get; set; }
    }

    abstract class AbstractShape : IShape
    {
        public int Id { get; set; }
        public string Text { get; set; }
    }

    class Line : AbstractShape
    {
        public Point A { get; set; }
        public Point B { get; set; }
    }

    class Rectangle : AbstractShape
    {
        public Point TopLeft { get; set; }
        public Point BottomRight { get; set; }
    }

    class Circle : AbstractShape
    {
        public Point Center { get; set; }
        public double Radius { get; set; }
    }

    class Point
    {
        public double X { get; set; }
        public double Y { get; set; }
    }
}

Here is the JSON output file generated by the Sender program:

{
  "Title": "Flowchart",
  "Shapes": [
    {
      "Center": {
        "X": 1.0,
        "Y": 5.0
      },
      "Radius": 1.25,
      "Id": 1,
      "Text": "Foo"
    },
    {
      "A": {
        "X": 2.25,
        "Y": 5.0
      },
      "B": {
        "X": 4.0,
        "Y": 5.0
      },
      "Id": 2,
      "Text": null
    },
    {
      "TopLeft": {
        "X": 4.0,
        "Y": 6.5
      },
      "BottomRight": {
        "X": 8.5,
        "Y": 3.5
      },
      "Id": 3,
      "Text": "Bar"
    }
  ]
}

Receiver

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace Receiver
{
    class Program
    {
        static void Main(string[] args)
        {
            string json = File.ReadAllText(@"C:\temp\test.json");

            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.Converters.Add(new FigureConverter());

            Chart chart = JsonConvert.DeserializeObject<Chart>(json, settings);

            Console.WriteLine(chart);
            Console.ReadKey();
        }
    }

    class FigureConverter : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(IFigure));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JObject jo = JObject.Load(reader);
            if (jo["Center"] != null)
            {
                return jo.ToObject<Circle>(serializer);
            }
            else if (jo["TopLeft"] != null)
            {
                return jo.ToObject<Rectangle>(serializer);
            }
            else
            {
                return jo.ToObject<Line>(serializer);
            }
        }

        public override bool CanWrite
        {
            get { return false; }
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            throw new NotImplementedException();
        }
    }

    class Chart
    {
        public string Title { get; set; }
        public List<IFigure> Shapes { get; set; }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("Chart: ");
            sb.AppendLine(Title);
            foreach (IFigure figure in Shapes)
            {
                sb.AppendLine(figure.ToString());
            }
            return sb.ToString();
        }
    }

    interface IFigure
    {
        int Id { get; set; }
        string Text { get; set; }
    }

    abstract class AbstractFigure : IFigure
    {
        public int Id { get; set; }
        public string Text { get; set; }
    }

    class Line : AbstractFigure
    {
        public Point A { get; set; }
        public Point B { get; set; }
        public override string ToString()
        {
            return string.Format("Line: A = {0}, B = {1}", A, B);
        }
    }

    class Rectangle : AbstractFigure
    {
        public Point TopLeft { get; set; }
        public Point BottomRight { get; set; }
        public override string ToString()
        {
            return string.Format("Rectangle: TopLeft = {0}, BottomRight = {1}", TopLeft, BottomRight);
        }
    }

    class Circle : AbstractFigure
    {
        public Point Center { get; set; }
        public double Radius { get; set; }
        public override string ToString()
        {
            return string.Format("Circle: Center = {0}, Radius = {1}", Center, Radius);
        }
    }

    class Point
    {
        public double X { get; set; }
        public double Y { get; set; }
        public override string ToString()
        {
            return string.Format("({0:0.##}, {1:0.##})", X, Y);
        }
    }
}

Here is the output of the Receiver program:

Chart: Flowchart
Circle: Center = (1, 5), Radius = 1.25
Line: A = (2.25, 5), B = (4, 5)
Rectangle: TopLeft = (4, 6.5), BottomRight = (8.5, 3.5)
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!