You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Json反序列化报错:无法将JObject转换为JToken的原因与解决

问题:反序列化JSON时抛出“Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken”异常

配置JSON

"printers": {
  "default": "Kyocera ECOSYS M6230cidn KX",
  "userMappings": [
    {
      "user": "050327",
      "printer": "SG Fanelli"
    },
    {
      "user": "050139",
      "printer": "SGPB"
    },
    {
      "user": "050115",
      "printer": "SG Holenstein"
    }
  ]
}

定义的DTO类

public class PrintersDto {
    public string Default { get; set; }
    public IEnumerable<UserPrinterDto> UserMappings { get; set; } = new List<UserPrinterDto>();
}

public class UserPrinterDto {
    public string User { get; set; }
    public string Printer { get; set; }
}

加载配置的代码

public PrintersDto GetPrintersConfig() {
    using (var configFileStream = FileIoService.ReadFile(ConfigFilePath)) {
        using (var reader = new StreamReader(configFileStream)) {
            var jsonString = reader.ReadToEnd();
            _configData = (JObject) JsonConvert.DeserializeObject(jsonString);

            var jtoken = _configData.SelectToken("printers");
            return jtoken.Value<PrintersDto>();
        }
    }
}

抛出的异常

Cannot cast Newtonsoft.Json.Linq.JObject to Newtonsoft.Json.Linq.JToken


异常原因

Value<T>()方法仅适用于从**值类型的JToken(如JValue)**中提取对应类型的值,而SelectToken("printers")返回的是JObject(JToken的子类,代表一个JSON对象),并非单纯的JValue,直接调用Value<T>()会触发类型转换失败的异常。

解决方法

有两种可行的修复方式:

方法1:使用ToObject<T>()替代Value<T>()

JObject提供的ToObject<T>()方法可以直接将自身反序列化为指定的DTO类型,修改后的代码如下:

public PrintersDto GetPrintersConfig() {
    using (var configFileStream = FileIoService.ReadFile(ConfigFilePath)) {
        using (var reader = new StreamReader(configFileStream)) {
            var jsonString = reader.ReadToEnd();
            _configData = (JObject) JsonConvert.DeserializeObject(jsonString);

            var jtoken = _configData.SelectToken("printers");
            return jtoken.ToObject<PrintersDto>(); // 替换为ToObject方法
        }
    }
}

方法2:直接反序列化为目标类型(更简洁)

如果不需要保留全局的_configData JObject,可以跳过中间解析步骤,直接完成反序列化:

// 子方式1:定义根对象类
public class ConfigRoot {
    public PrintersDto Printers { get; set; }
}

public PrintersDto GetPrintersConfig() {
    using (var configFileStream = FileIoService.ReadFile(ConfigFilePath)) {
        using (var reader = new StreamReader(configFileStream)) {
            var jsonString = reader.ReadToEnd();
            var root = JsonConvert.DeserializeObject<ConfigRoot>(jsonString);
            return root.Printers;
        }
    }
}

// 子方式2:直接反序列化printers节点
public PrintersDto GetPrintersConfig() {
    using (var configFileStream = FileIoService.ReadFile(ConfigFilePath)) {
        using (var reader = new StreamReader(configFileStream)) {
            var jsonString = reader.ReadToEnd();
            var jObject = (JObject)JsonConvert.DeserializeObject(jsonString);
            return JsonConvert.DeserializeObject<PrintersDto>(jObject["printers"].ToString());
        }
    }
}

内容的提问来源于stack exchange,提问作者BennoDual

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 12:45:46