C# 在一个程序集中序列化,在另一个程序集中反序列化?
我在两个项目中使用了相同的类,一个在C# 在一个程序集中序列化,在另一个程序集中反序列化?,c#,serialization,json.net,protobuf-net,binaryformatter,C#,Serialization,Json.net,Protobuf Net,Binaryformatter,我在两个项目中使用了相同的类,一个在运行时上发送给另一个进程,该进程必须反序列化该对象并使用它(假定两个对象是相同的,但程序集名称不同,因此它们实际上被解释为两种不同的类型)。根据我的研究,我提出了一些不可行的解决方案,原因如下 Json.NET:给出两种类型不兼容的例外情况(尝试在序列化设置中使用typename.all) protobuf-net:要求我在任何地方添加属性,或者只为其提供属性名称(在v2中),由于我的对象太复杂,这两种方法对我来说都是不可能的 BinaryFormatter:
运行时
上发送给另一个进程,该进程必须反序列化该对象并使用它(假定两个对象是相同的,但程序集名称不同,因此它们实际上被解释为两种不同的类型)。根据我的研究,我提出了一些不可行的解决方案,原因如下
Json.NET
:给出两种类型不兼容的例外情况(尝试在序列化设置中使用typename.all)
protobuf-net
:要求我在任何地方添加属性,或者只为其提供属性名称(在v2中),由于我的对象太复杂,这两种方法对我来说都是不可能的
BinaryFormatter
:与protobuf相同的原因->大量属性
使用公共程序集
:由于一些与我的项目架构相关的原因,我不能
那么,有没有简单的方法将一个类型序列化,然后将其反序列化为另一个类型(实际上是同一个类,但在不同的程序集中) 是的,完全可以使用一个程序集中的类进行序列化,并使用Json.Net反序列化为另一个程序集中的类。事实上,这首先是序列化的主要用例之一——在不同系统之间传输数据 您需要记住两件事:
typenameholling
设置设置为None
(我认为这是默认设置)。如果包含类型名元数据,那么Json.Net将期望在接收端找到这些程序集,而反序列化将失败,因为这些程序集不在那里JsonConverter
类来处理反序列化。当Json.Net看到一个接口时,它不知道要创建什么类型的具体类,因为它可以是任何类型。转换器可以查找JSON中可能存在的其他数据,并告诉JSON.Net实例化哪个具体类。如果JSON中没有明显的数据段可用作类型的指示符,则可以使用序列化端的转换器添加自定义指示符JsonConverter
来处理创建正确的IFigure
实例,使用JSON中的某些属性作为指示符
发件人
接受者
两个程序集是否都可以引用一个公共程序集?我唯一能想到的另一件事是在不使用任何名称空间的情况下使用XML。到目前为止,最好的解决方案是使用一个公共库。@DanielEugen为什么程序集信息会被序列化?序列化的结果应该可以完全转移到另一个运行时或语言。它不应该关心源程序集元数据。@DanielEugen,在使用JSON.NET时,请尝试
TypeNameHandling.None
而不是TypeNameHandling.All
。All
值告诉序列化程序包含所有对象的类型信息,该类型信息可能是导致不兼容错误的原因。将其设置为None
将排除所有类型信息。您可以检查序列化对象中的$type属性,以验证是否包含类型信息。@在Json.NET中,我试图为反序列化程序提供TypeNameAssemblyStyle=FormatterAssemblyStyle.Simple
设置,该设置本应忽略程序集名称的更改,但我仍然获得中指定的类型JSON与异常不兼容。
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; }
}
}
{
"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);
}
}
}
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)