在一个程序集中序列化,在另一个程序集中反序列化?

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

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

protobuf-net :要求我在每个地方添加属性或者只是为它提供属性名称(在v2中),由于我的对象太复杂,这对我来说都是不可能的。

BinaryFormatter :与protobuf->吨属性相同的原因。

Use Common Assembly :由于某些与我的项目架构相关的原因,我不能。

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

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

您需要记住两件事:

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

下面是一些示例代码,用于演示我已经提出的概念。 该演示分为两部分。 第一部分是“发送者”,它将组成的“图”类结构序列化为JSON并将其写入文件。 第二部分是“接收器”,它读取文件并将JSON反序列化为一组不同的类。 您会注意到我有意在接收器中创建了一些与发件人不同的类名,但它们具有相同的属性名称和结构,因此它仍然有效。 您还会注意到接收器程序使用自定义JsonConverter来处理使用JSON中某些属性作为指示符来创建正确的IFigure实例。

寄件人

 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 { 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 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输出文件:

 { "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(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(serializer); } else if (jo["TopLeft"] != null) { return jo.ToObject(serializer); } else { return jo.ToObject(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 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程序的输出:

 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)