C#使用Newtonsoft.Json反序列化报错:无法将类型为“Newtonsoft.Json.Linq.JObject”的对象强制转换

  • Post author:
  • Post category:其他




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反序列化时遇到的一个问题。如果有更好的解决方案,欢迎留言交流。



版权声明:本文为qq_34769196原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。