1、问题描述
C#使用Newtonsoft.Json将 一般对象
序列化和反序列化为json时,一般使用 SerializeObject()
和 DeserializeObject()
即可。
但是,当对象中包含一个自定义集合对象时,仅仅使用DeserializeObject()
无法正确实现反序列化。
有可能报错:
无法将类型为“Newtonsoft.Json.Linq.JObject”的对象强制转换
2、代码说明
直接用一段示例代码,进行说明。
2.1 准备阶段
示例准备3个类:
Action
类:表示一个动作。
class Action
{
public Action()
{
}
public Action(string name, int step)
{
m_name = name;
m_step = step;
}
public override string ToString()
{
return $"Action Name:{m_name}, Step: {m_step.ToString()}";
}
private string m_name; // 动作名称
private int m_step; // 动作步骤
public string Name { get => m_name; set => m_name = value; }
public int Step { get => m_step; set => m_step = value; }
}
ActionCollection
类:表示一个动作的集合类。
class ActionCollection : CollectionBase
{
public void Add(Action action)
{
this.InnerList.Add(action);
}
}
Cat
类:猫类,Cat
对象包含一个 ActionCollection
类实例。
class Cat
{
private string m_name; // 猫的名字
private ActionCollection m_actions; // 具备的动作集合
public Cat()
{
}
public Cat(string name, ActionCollection ac)
{
this.m_name = name;
this.m_actions = ac;
}
public string Name { get => m_name; set => m_name = value; }
public ActionCollection Actions { get => m_actions; set => m_actions = value; }
}
2.2 序列化
使用 SerializeObject()
方法将一个 Cat
对象序列化为Json,并存储到文件中。
/// <summary>
/// 序列化一个Cat对象到Json
/// </summary>
/// <param name="cat"></param>
/// <param name="jsonPath"></param>
public static void Save(Cat cat, string jsonPath)
{
string jsonString = JsonConvert.SerializeObject(cat);
File.WriteAllText(jsonPath, jsonString);
}
2.3 反序列化
简单地使用 DeserializeObject()
方法从json文件中读取json字符串,并反序列化为一个 Cat
对象。
/// <summary>
/// 反序列化(错误方法)
/// </summary>
/// <param name="jsonPath"></param>
public static Cat Load(string jsonPath)
{
string jsonString = File.ReadAllText(jsonPath);
Cat cat = JsonConvert.DeserializeObject<Cat>(jsonString);
return cat;
}
使用测试代码进行调试,发现会报错:
无法将类型为“Newtonsoft.Json.Linq.JObject”的对象强制转换为Action。
原因说明:
简单地使用 DeserializeObject()
方法进行反序列化时,只会将 ActionCollection
集合类实例中的元素反序列化为一个JObject
对象。
JObject
对象无法隐式转换为Action
类对象,因而会报错。
解决方案:
由于使用 DeserializeObject()
方法无法正确地将“集合对象字段”的元素反序列化出来。因此,需要手动修正。
代码如下:
/// <summary>
/// 反序列化(正确方法)
/// </summary>
/// <param name="jsonPath"></param>
/// <returns></returns>
public static Cat LoadJson(string jsonPath)
{
string jsonString = File.ReadAllText(jsonPath);
Cat cat = JsonConvert.DeserializeObject<Cat>(jsonString);
ActionCollection actions = new ActionCollection();
foreach(var item in cat.Actions)
{
string itemString = item.ToString();
Action ac = JsonConvert.DeserializeObject<Action>(itemString);
actions.Add(ac);
}
cat.Actions = actions;
return cat;
}
再次使用测试代码进行调试,可以发现问题解决。
3、测试代码
如果需要测试报错,需要取消“错误方法取出猫”的注释。
static void Main(string[] args)
{
// 准备一只猫
Action run = new Action("Running", 2);
Action jump = new Action("Jump", 2);
ActionCollection actions = new ActionCollection();
actions.Add(run);
actions.Add(jump);
Cat helloKitty = new Cat("HelloKitty", actions);
// 将猫放入json
string jsonPath = "cat.json";
Save(helloKitty, jsonPath);
错误方法取出猫
//Cat helloKittyClone = Load(jsonPath);
//Console.WriteLine(helloKittyClone.Name);
//foreach (Action x in helloKittyClone.Actions)
//{
// Console.WriteLine(x.ToString());
//}
// 正确方法取出猫
Cat helloKittyCloneX = LoadJson(jsonPath);
Console.WriteLine(helloKittyCloneX.Name);
foreach (Action x in helloKittyCloneX.Actions)
{
Console.WriteLine(x.ToString());
}
}
代码附件:Github传送门
以上为C#使用Newtonsoft.Json反序列化时遇到的一个问题。如果有更好的解决方案,欢迎留言交流。