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

.NET Framework 4.7.2 Newtonsoft.Json反序列化嵌套JSON异常

解决Newtonsoft.Json反序列化混合类型Value字段的异常问题

问题背景

在.NET Framework 4.7.2环境下,调用Web API获取数据并使用Newtonsoft.Json反序列化时,API返回的时间/值对数组中,Value字段存在两种格式:

  • 正常情况:Value为普通数值,反序列化正常
  • 异常/无数据情况:Value为嵌套JSON对象,此时抛出异常:

    Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Object' because the type requires a JSON primitive value

问题原因

Newtonsoft.Json在反序列化object类型时,默认仅支持JSON原始值(字符串、数字、布尔、null)的转换。当遇到JSON对象时,由于无法自动推断对应的.NET类型,会直接抛出上述异常。

解决方案

以下提供三种可行的解决方式,根据需求选择:

方案1:用JToken替代object类型(推荐)

将PiValue类的Value属性类型改为JToken,它可以兼容任何JSON元素(数值、对象、数组等),再在属性逻辑中统一处理为业务需要的double值:

[JsonObject]
public class PiValue 
{
    private DateTime _Timestamp = DateTime.MinValue;
    private double _Value = 0d;

    /// <summary>
    /// Always gets set to Local Time
    /// </summary>
    [JsonProperty]
    public DateTime Timestamp
    {
        get { return _Timestamp; }
        set
        {
            _Timestamp = value.ToLocalTime();
        }
    }

    [JsonProperty]
    public JToken Value
    {
        get { return JToken.FromObject(_Value); }
        set
        {
            if (value.Type == JTokenType.Object)
            {
                // 嵌套对象直接设为NaN
                _Value = double.NaN;
            }
            else
            {
                // 尝试转换为double,失败则设为NaN
                _Value = value.ToObject<double?>() ?? double.NaN;
            }
        }
    }

    // 可选:对外暴露处理后的数值(忽略JSON序列化)
    [JsonIgnore]
    public double ProcessedValue => _Value;
}

方案2:自定义JsonConverter处理object类型

若需保留object类型,可自定义转换器处理JSON对象的反序列化:

第一步:创建转换器

public class ObjectOrPrimitiveConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(object);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.StartObject)
        {
            // 将JSON对象转为JObject,方便后续判断
            return JObject.Load(reader);
        }
        // 原始值直接返回
        return serializer.Deserialize(reader);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}

第二步:在属性上标记使用转换器

[JsonObject]
public class PiValue 
{
    private DateTime _Timestamp = DateTime.MinValue;
    private object _Value = 0d;

    [JsonProperty]
    public DateTime Timestamp
    {
        get { return _Timestamp; }
        set
        {
            _Timestamp = value.ToLocalTime();
        }
    }

    [JsonProperty, JsonConverter(typeof(ObjectOrPrimitiveConverter))]
    public object Value
    {
        get { return _Value; }
        set
        {
            if (_Value != value)
            {
                double val = 0;
                if (value is null)
                    _Value = double.NaN;
                else if (value is JObject)
                    // 识别到嵌套对象,设为NaN
                    _Value = double.NaN;
                else if (double.TryParse(value.ToString(), out val))
                    _Value = val;
                else
                    _Value = double.NaN;
            }
        }
    }
}

方案3:保留异常对象信息(如需业务处理)

若需要保留嵌套对象的详细信息,可定义对应实体类,通过JToken区分处理:

// 定义异常对象的实体类
public class ShutdownInfo
{
    public string Name { get; set; }
    public int Value { get; set; }
    public bool IsSystem { get; set; }
}

[JsonObject]
public class PiValue 
{
    private DateTime _Timestamp = DateTime.MinValue;
    private double _Value = 0d;
    private ShutdownInfo _ShutdownInfo;

    [JsonProperty]
    public DateTime Timestamp
    {
        get { return _Timestamp; }
        set
        {
            _Timestamp = value.ToLocalTime();
        }
    }

    [JsonProperty]
    public JToken Value
    {
        set
        {
            if (value.Type == JTokenType.Object)
            {
                // 解析为异常对象
                _ShutdownInfo = value.ToObject<ShutdownInfo>();
                _Value = double.NaN;
            }
            else
            {
                _ShutdownInfo = null;
                _Value = value.ToObject<double?>() ?? double.NaN;
            }
        }
    }

    [JsonIgnore]
    public double ProcessedValue => _Value;

    [JsonIgnore]
    public ShutdownInfo ShutdownInfo => _ShutdownInfo;
}

补充说明

  • 为何改成string类型仍报错?因为Newtonsoft.Json反序列化string类型时,仅支持JSON字符串原始值,遇到JSON对象会直接抛出异常,无法自动将对象转为字符串。
  • 为何他人同版本能成功?可能对方配置了全局Json序列化设置(如TypeNameHandling)、使用了自定义转换器,或实体类定义不同(如用JToken替代object)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 01:52:17