是的,绝对可以在一个程序集中使用类进行序列化,并使用 Json.Net 将其反序列化为另一个程序集的类。事实上,这首先是序列化的主要用例之一——在不同系统之间传输数据。
有两点需要牢记:
- 如果您的源程序集和目标程序集不同,那么您应该不将实际的完全限定类型名称作为元数据包含在 JSON 中。换句话说,确保将
TypeNameHandling 设置设置为None(我相信这是默认设置)。如果您包含类型名称元数据,那么 Json.Net 将期望在接收端找到这些程序集,并且反序列化将失败,因为这些程序集不存在。
- 如果您在类结构中使用接口而不是具体类型,则需要创建一个或多个
JsonConverter 类来处理反序列化。当 Json.Net 看到一个接口时,它不知道要创建什么类型的具体类,因为它可能是任何东西。转换器可以查找 JSON 中可能存在的其他数据,并告诉 Json.Net 要实例化哪个具体类。如果 JSON 中没有明显的数据可以作为类型的指标,可以在序列化端使用转换器添加自定义指标。
这里有一些示例代码来演示我所阐述的概念。演示分为两部分。第一部分是“发送者”,它将一个组成的“图表”类结构序列化为 JSON 并将其写入文件。第二部分是“接收器”,它读取文件并将 JSON 反序列化为一组不同的类。你会注意到我故意使接收者中的一些类名与发送者不同,但它们具有相同的属性名和结构,所以它仍然有效。您还会注意到接收器程序使用自定义 JsonConverter 来处理创建正确的 IFigure 实例,并使用 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; }
}
}
这是 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<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 程序的输出:
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)