![](/img/trans.png)
[英]JSON.NET - How do I include Type Name Handling for primitive C# types that are stored in an array/list as Object type
[英]Overriding Default Primitive Type Handling in Json.Net
有没有办法在处理原始类型时覆盖Json.net的默认反序列化行为? 例如,当将json数组[3.14,10,"test"]
反序列[3.14,10,"test"]
一种object[]
3.14将是double
类型, 10将是long
类型。 无论如何我可以拦截或覆盖这种类型的决定,所以我可以分别将值反序列化为decimal
和int
?
我基本上总是希望json整数总是作为int
返回并且浮点数以decimal
返回。 这将节省我一些必须在我的代码中注入double
到decimal
转换。
我已经考虑扩展Newtonsoft.Json.Serialization.DefaultContractResolver
并实现我自己的Newtonsoft.Json.JsonConverter
但我还没有发现任何方法来实现这个所需的覆盖。
重现的示例代码
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}
我认为,这应该有效
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));
不幸的是,方法JsonReader.SetToken(JsonToken, Object, Boolean)
不再是虚拟的。 在更新版本的Json.NET( 10.0.1或更高版本)中,必须覆盖JsonReader.Read()
并在那里进行必要的转换,然后使用所需的值类型更新读者的值。
例如,如果您希望JsonTextReader
返回Int32
而不是Int64
,则以下阅读器和扩展方法将完成此任务:
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);
}
}
}
然后使用如下:
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())));
笔记:
JsonSerializer
和JsonReader
都有一个设置FloatParseHandling
,它控制JSON中的浮点数最初是解析为double
还是decimal
。 因此,没有理由在Read()
手动实现此转换。
通过使用PreferInt32JsonTextReader
您可以控制序列化程序如何反序列化object
类型的值。 之前的整数JSON值将无条件地反序列化为long
(如果需要,则为BigInteger
)。 现在将返回int
如果可能的话。 这也将修改DataTableConverter
推断列类型的方式。
然而,使用PreferInt32JsonTextReader
加载JSON到时会不会影响发生了什么JToken
层次有,比方说, JToken.Load()
因为建立层次结构,方法JsonWriter.WriteToken()
会自动将所有整数值转换为long
。
这里有初步单元测试的样品来源。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.