唐元志的技术博客 软件设计与开发

采用JSON.NET序列化接口属性

2021-05-25
Michael
阅读:

当你的对象中的一个属性(Property)是一个接口,这个接口有几个实现的具体类时,如果采用 JSON.NET 进行简单快速的序列化和反序列化呢?

比如这个例子,一个 Message, 他的 Header 是一个接口,同时 Message 自己也是一个抽象类,它有两个子类分别是 HttpMessageRpcMessage.

public class Message
{
	public IMessageHeader Header { get; set; }

	public object Body { get; set; }

	public Message()
	{

	}
}

public class HttpMessage : Message
{

}

public class RpcMessage : Message
{

}

Header 又分为 HttpHeaderRpcHeader

public interface IMessageHeader
{
	string Name { get; set; }
}

public class HttpHeader : IMessageHeader
{
	public string Name { get; set; } = "Http";
}

public class RpcHeader : IMessageHeader
{
	public string Name { get; set; } = "Rpc";
}

下面我们来创建一些 Message

	var messageList = new List<Message>
	{
		new HttpMessage()
		{
			Header = new HttpHeader(),
			Body = new byte[] { 1, 2, 3 }
		},
		new RpcMessage()
		{
			Header = new RpcHeader(),
			Body = new byte[] { 4, 5, 6 }
		}
	};

采用默认的对象去序列化这个 messageList

	var jsonString = JsonConvert.SerializeObject(messageList);

产生的 JSON 数据将会如下。

[
  { "Header": { "Name": "Http" }, "Body": "AQID" },
  { "Header": { "Name": "Rpc" }, "Body": "BAUG" }
]

但是当我们将 Json 反序列化为原始对象时

	var messages = JsonConvert.DeserializeObject<List<Message>>(jsonString);

将会遇到如下错误

Newtonsoft.Json.JsonSerializationException: 'Could not create an instance of type JSON_DEMO.IMessageHeader. Type is an interface or abstract class and cannot be instantiated. Path '[0].Header.Name', line 1, position 19.'

主要原因是 JSON.NET 本身并不知道它应该发序列化为哪一个具体的子类,为了解决这个问题,如果我们可以在序列化对象时,将子类的信息同时序列化到 Json 数据中,那么反序列化回对象时,就可以知道具体应该反序列化成哪一个具体的子类。

JSON.NET 提供了一个解决方案,在序列化和反序列化时,指定如下的设置。

	JsonSerializerSettings settings = new JsonSerializerSettings
	{
		TypeNameHandling = TypeNameHandling.Auto
	};

当序列化对象时,指定这个 settings

var jsonString = JsonConvert.SerializeObject(messageList, settings);

现在我们将会得到如下的 Json

[
  {
    "$type": "JSON_DEMO.HttpMessage, JSON_DEMO",
    "Header": { "$type": "JSON_DEMO.HttpHeader, JSON_DEMO", "Name": "Http" },
    "Body": { "$type": "System.Byte[], mscorlib", "$value": "AQID" }
  },
  {
    "$type": "JSON_DEMO.RpcMessage, JSON_DEMO",
    "Header": { "$type": "JSON_DEMO.RpcHeader, JSON_DEMO", "Name": "Rpc" },
    "Body": { "$type": "System.Byte[], mscorlib", "$value": "BAUG" }
  }
]

当我们反序列化这个 Json 成 List<Message>是,将可以得到原始的对象。

var messages = JsonConvert.DeserializeObject<List<Message>>(jsonString, settings);

完整代码

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

namespace JSON_DEMO
{
	class Program
	{
		static void Main(string[] args)
		{
			var messageList = new List<Message>
			{
				new HttpMessage()
				{
					Header = new HttpHeader(),
					Body = new byte[] { 1, 2, 3 }
				},
				new RpcMessage()
				{
					Header = new RpcHeader(),
					Body = new byte[] { 4, 5, 6 }
				}
			};

			JsonSerializerSettings settings = new JsonSerializerSettings
			{
				TypeNameHandling = TypeNameHandling.Auto
			};

			var jsonString = JsonConvert.SerializeObject(messageList, settings);
			var messages = JsonConvert.DeserializeObject<List<Message>>(jsonString, settings);
		}
	}

	public class Message
	{
		public IMessageHeader Header { get; set; }

		public object Body { get; set; }

		public Message()
		{

		}
	}

	public class HttpMessage : Message
	{

	}

	public class RpcMessage : Message
	{

	}

	public interface IMessageHeader
	{
		string Name { get; set; }
	}

	public class HttpHeader : IMessageHeader
	{
		public string Name { get; set; } = "Http";
	}

	public class RpcHeader : IMessageHeader
	{
		public string Name { get; set; } = "Rpc";
	}
}


类似文章

Comments