【问题标题】:JsonConvert.DeserializeObject throws an exception when deserializing JSON with a hex value into an sbyte property将具有十六进制值的 JSON 反序列化为 sbyte 属性时,JsonConvert.DeserializeObject 引发异常
【发布时间】:2019-07-25 17:03:18
【问题描述】:

我有一个机器生成的类MyData,它有sbyte 成员。实际的类很长而且可读性不强,但这里是它的一个片段:

class MyData
{
    private sbyte _MuxControl;
    public sbyte MuxControl 
    { 
        get { return _MuxControl; } 
        set { __isset.MuxControl = true; this._MuxControl = value; }
    }
}

对应的简化 JSON 如下所示:

[ 
  { 
    "MuxControl": 0xAA
  }
]

我正在尝试像这样反序列化:

var deserialized = JsonConvert.DeserializeObject<List<MyData>>(JsonStr);

某些值超出了sbyte 的范围,例如0xAA。结果,抛出异常。例如,当我将值更改为0x1 时,它可以工作。

我无法触摸MyData 的代码。它是机器生成的。是否有转换设置、覆盖或其他方式让这些值正确反序列化为sbyte

【问题讨论】:

  • 您能否分享您尝试反序列化的 JSON、MyData 的定义以及其中一个值超出范围时所需的处理方式?
  • @BrianRogers 当然。正如我所写,MyData 是机器生成的,因此很长且不可读。我可以分享它的片段:private sbyte _MuxControl;public sbyte MuxControl { get { return _MuxControl; } set { __isset.MuxControl = true; this._MuxControl = value; } }Json 有东西"MuxControl": 0xAA,

标签: c# json reflection json.net jsonconverter


【解决方案1】:

您得到了例外,因为 Json.Net 在幕后为 sbyte 使用的转换方法是范围检查的,但您真正需要的是未经检查的转换(或更准确地说,更大的范围)。您可以使用自定义 JsonConverter 来处理它,如下所示:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Integer)
        {
            // Integer values come in as longs from the reader.
            long val = (long)reader.Value;

            // If the value fits in 8 bits, convert it to a signed byte.
            if (val >= -128 && val <= 255)
            {
                return unchecked((sbyte)val);
            }

            // We got a value that can't fit in an sbyte.
            throw new JsonSerializationException("Value was out of range for an sbyte: " + val);
        }

        // We got something we didn't expect, like a string or object.
        throw new JsonSerializationException("Unexpected token type: " + reader.TokenType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        // Write sbyte values out in the same format we read them.
        // Note this is technically invalid JSON per the spec.
        writer.WriteRawValue("0x" + ((sbyte)value).ToString("X2"));
    }
}

要使用转换器,请将其实例传递给JsonConvert.DeserializeObject,如下所示:

var deserialized = JsonConvert.DeserializeObject<List<MyData>>(JsonStr, new SByteConverter());

工作演示:https://dotnetfiddle.net/fEW6wy

【讨论】:

  • sbyte(或 sbyte.MinValue/sbyte.MaxValue)不应该是 +127 吗?
  • @ivo 通常,是的。但是我们在这里试图解决的整个问题是允许高于 127,但仍适合 8 位的值,例如 170 (0xAA) 被转换为每个 OP 的 sbyte要求。 unchecked 关键字允许我们在不抛出异常的情况下做到这一点。我选择将范围的下限保留为 -128 而不是 0,以防万一在数据中碰巧有 sbyte 值而不是 MuxControl 表示为负整数。我想让那些仍然正常转换。
  • 啊,是的。现在它是有道理的。非常感谢您澄清这一点
猜你喜欢
  • 2020-03-18
  • 2020-08-22
  • 1970-01-01
  • 1970-01-01
  • 2018-04-26
  • 2019-07-21
  • 1970-01-01
  • 1970-01-01
  • 2012-08-19
相关资源
最近更新 更多