在一个程序集中进行序列化,而在另一个程序集中进行反序列化? [英] Serialize in one assembly, and de-serialize in another?

查看:84
本文介绍了在一个程序集中进行序列化,而在另一个程序集中进行反序列化?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在两个项目中有相同的类,一个在runtime上发送到另一个必须反序列化该对象并使用它的进程(假定两个对象相同,但程序集名称不同,所以它们实际上被解释为两种不同的类型).根据我的研究,由于以下原因,我提出了无法使用的解决方案.

I have the same class in two projects one is being sent on runtime to the other process that has to de-serialize that object and use it (giving that the two objects are the same but differ in assembly name so they are actually interpreted as two different types). From my research i have came with those solutions that doesn't work for the following reasons.

Json.NET:给我一个例外,这两种类型不兼容(在序列化设置中使用typename.all进行尝试).

Json.NET: giving me an exceptions that the two types aren't compatible (tried using typename.all in serialization settings).

protobuf-net:要求我在每个位置添加属性,或仅在属性中提供属性名称(在v2中),由于我的对象太复杂,所以这两个对我来说都是不可能的.

protobuf-net: requires me to add attributes every where or simply provide it with the properties name (in v2), which both aren't possible for me due to the fact that my object is too complex.

BinaryFormatter:与protobuf->大量属性的原因相同.

BinaryFormatter: same reasons as protobuf-> tons of attributes.

Use Common Assembly:由于某些原因,我无法实现我的项目的体系结构.

Use Common Assembly: For some reasons related to the architecture of my project i can't.

那么有什么简单的方法来序列化一个类型然后将其反序列化为另一种类型(实际上是同一类,但在不同的程序集中)?

So is there any simple way to serialize one type then de-serializing it to another type (which is virtually the same class but in different assembly) ?

推荐答案

是的,使用Json.Net在一个程序集中使用类进行序列化并反序列化为另一个程序集的类是绝对可能的.实际上,这首先是序列化的主要用例之一-在不同系统之间传输数据.

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.

您需要记住两件事:

  1. 如果源程序集和目标程序集不同,则您应该在JSON中包括实际的完全限定类型名称作为元数据.换句话说,请确保将TypeNameHandling设置设置为None(我相信这是默认设置).如果包含类型名称元数据,那么Json.Net将期望在接收方找到那些程序集,并且反序列化将失败,因为这些程序集不存在.
  2. 如果在类结构中使用接口而不是具体类型,则需要创建一个或多个JsonConverter类来处理反序列化.当Json.Net看到一个接口时,它将不知道要创建哪种类型的具体类,因为它可以是任何东西.转换器可以查找JSON中可能存在的其他数据,并告诉Json.Net实例化哪个具体类.如果JSON中没有明显的数据可用作该类型的指示符,则可以在序列化端使用转换器来添加自定义指示符.
  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.

这里有一些示例代码来演示我提出的概念.该演示分为两个部分.第一部分是发送者",它将已编成的关系图"类结构序列化为JSON并将其写入文件.第二部分是接收器",它读取文件并将JSON反序列化为一组不同的类.您会注意到,我故意使接收者中的某些类名称不同于发送者,但是它们具有相同的属性名称和结构,因此它仍然有效.您还将注意到,接收器程序使用定制的JsonConverter来处理正确的IFigure实例,并使用JSON中的某些属性作为指示符.

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.

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

这是Sender程序生成的JSON输出文件:

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"
    }
  ]
}

接收器

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

这是Receiver程序的输出:

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)

这篇关于在一个程序集中进行序列化,而在另一个程序集中进行反序列化?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆