首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >重写Json.Net中的默认基元类型处理

重写Json.Net中的默认基元类型处理
EN

Stack Overflow用户
提问于 2012-03-28 19:25:25
回答 2查看 5.2K关注 0票数 7

在处理原语类型时,是否有一种方法可以覆盖Json.net的默认反序列化行为?例如,当将json数组反序列化为[3.14,10,"test"]类型为object[]时,3.14为double类型,10为long类型。是否可以截取或重写此类型的决定,以便将值分别反序列化为decimalint

基本上,我总是希望json整数始终以int的形式返回,而浮点数以decimal的形式返回。这将使我不必在代码中将double注入到decimal转换。

我已经研究过扩展Newtonsoft.Json.Serialization.DefaultContractResolver和实现我自己的Newtonsoft.Json.JsonConverter,但是我还没有找到任何方法来实现这个想要的覆盖。

要复制的示例代码

代码语言:javascript
复制
object[] variousTypes = new object[] {3.14m, 10, "test"};
string jsonString = JsonConvert.SerializeObject(variousTypes);
object[] asObjectArray = JsonConvert.DeserializeObject<object[]>(jsonString); // Contains object {double}, object {long}, object {string}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-03-28 21:41:17

我想,这应该能行

代码语言:javascript
复制
public class MyReader : JsonTextReader
{
    public MyReader(string s) : base(new StringReader(s))
    {
    }

    protected override void SetToken(JsonToken newToken, object value)
    {
        object retObj = value;
        if (retObj is long) retObj = Convert.ChangeType(retObj, typeof(int));
        if (retObj is double) retObj = Convert.ChangeType(retObj, typeof(decimal));

        base.SetToken(newToken, retObj);
    }
}


object[] variousTypes = new object[] { 3.14m, 10, "test" };
string jsonString = JsonConvert.SerializeObject(variousTypes);

JsonSerializer serializer = new JsonSerializer();
var asObjectArray = serializer.Deserialize<object[]>(new MyReader(jsonString));
票数 1
EN

Stack Overflow用户

发布于 2019-02-08 01:17:47

不幸的是,JsonReader.SetToken(JsonToken, Object, Boolean)方法不再是虚拟的。在最近版本的Json.NET (10.0.1或更高版本)中,必须覆盖JsonReader.Read()并在那里进行必要的转换,然后用所需的值类型更新阅读器的值。

例如,如果您希望您的JsonTextReader尽可能地返回Int32而不是Int64,下面的读取器和扩展方法将完成此工作:

代码语言:javascript
复制
public class PreferInt32JsonTextReader : JsonTextReader
{
    public PreferInt32JsonTextReader(TextReader reader) : base(reader) { }

    public override bool Read()
    {
        var ret = base.Read();

        // Read() is called for both an untyped read, and when reading a value typed as Int64
        // Thus if the value is larger than the maximum value of Int32 we can't just throw an 
        // exception, we have to do nothing.
        // 
        // Regardless of whether an Int32 or Int64 is returned, the serializer will always call
        // Convert.ChangeType() to convert to the final, desired primitive type (say, Uint16 or whatever).
        if (TokenType == JsonToken.Integer
            && ValueType == typeof(long)
            && Value is long)
        {
            var value = (long)Value;

            if (value <= int.MaxValue && value >= int.MinValue)
            {
                var newValue = checked((int)value); // checked just in case
                SetToken(TokenType, newValue, false);
            }
        }

        return ret;
    }
}

public static class JsonExtensions
{
    public static T PreferInt32DeserializeObject<T>(string jsonString, JsonSerializerSettings settings = null)
    {
        using (var sw = new StringReader(jsonString))
        using (var jsonReader = new PreferInt32JsonTextReader(sw))
        {
            return JsonSerializer.CreateDefault(settings).Deserialize<T>(jsonReader);
        }
    }
}

然后按以下方式使用:

代码语言:javascript
复制
object[] variousTypes = new object[] { 3.14m, 10, "test" };
string jsonString = JsonConvert.SerializeObject(variousTypes);
var settings = new JsonSerializerSettings
{
    FloatParseHandling = FloatParseHandling.Decimal,
};
object[] asObjectArray = JsonExtensions.Int32PreferredDeserializeObject<object[]>(jsonString, settings);
// No assert
Assert.IsTrue(variousTypes.Select(o => o == null ? null : o.GetType()).SequenceEqual(asObjectArray.Select(o => o == null ? null : o.GetType())));

备注:

  • JsonSerializerJsonReader都有一个设置FloatParseHandling,它控制来自JSON的浮点数最初被解析为double还是decimal。因此,没有理由在Read()中手动实现此转换。
  • 通过使用PreferInt32JsonTextReader,您可以控制序列化程序如何反序列化object类型的值。以前,整数JSON值将无条件地反序列化为long (如果需要,则为BigInteger )。现在,如果可能的话,将返回int。这还将修改DataTableConverter如何推断列类型。
  • 然而,使用PreferInt32JsonTextReader不会影响在JToken层次结构中加载JSON时发生的事情,比如JToken.Load(),因为构建层次结构的方法JsonWriter.WriteToken()会自动将所有整数值转换为long

样本源与初步单元测试这里

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9914333

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档