如何更改数字反序列化的默认类型?

我将一些属性反序列化为Dictionary

当我反序列化一些json时,它用Int64对象而不是Int32填充Dictionary 。 我希望它选择Int32作为默认,知道我可以有转换溢出的javascript数字。 在这种情况下抛出exception是完全可以接受的。

有没有办法实现这一目标? 我希望有一些很好的属性或一个方便的接口,可以实现并添加到JsonSerializer 。 而且我担心我必须深入到Json.NET的深处。

基本上我想有一些方法来控制对象的已知类型,以便我可以获得Int32而不是Int64DateTimes而不是Strings

据我所知,没有内置的方法可以做到这一点。

关于这个问题有一个问题 ,但它已经关闭。 作者对此问题的一些评论:

默认情况下,Json.NET将整数值作为Int64读取,因为无法知道该值是Int32还是Int64,并且Int64不太可能溢出。 对于类型化属性,反序列化器知道将Int64转换为Int32,但由于您的属性是无类型的,因此您将获得Int64。 […]这就是Json.NET必须工作的方式。

最简单的解决方案是将类型更改为Dictionary ,但我认为您不仅仅是阅读数字而且因此被object所困扰。

另一个选择是使用序列化回调并手动将这些Int64转换为Int32或创建自己的 合同解决方案 JsonConverter并直接控制(反)序列化。


编辑:我创建了一个更具体的例子。

这是一个非常基本的转换器,只适用于您的特定字典:

 public class Int32Converter : JsonConverter { public override bool CanConvert(Type objectType) { // may want to be less concrete here return objectType == typeof(Dictionary); } public override bool CanWrite { // we only want to read (de-serialize) get { return false; } } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // again, very concrete Dictionary result = new Dictionary(); reader.Read(); while (reader.TokenType == JsonToken.PropertyName) { string propertyName = reader.Value as string; reader.Read(); object value; if (reader.TokenType == JsonToken.Integer) value = Convert.ToInt32(reader.Value); // convert to Int32 instead of Int64 else value = serializer.Deserialize(reader); // let the serializer handle all other cases result.Add(propertyName, value); reader.Read(); } return result; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { // since CanWrite returns false, we don't need to implement this throw new NotImplementedException(); } } 

您可以使用属性来使用转换器装饰成员,也可以将其作为参数传递给(反)序列化方法。 这是我使用属性的示例:

  [JsonObject] public class MyObject { [JsonConverter(typeof(Int32Converter))] public Dictionary Properties { get; set; } } 

这是我用来测试实现的代码:

 class Program { static void Main(string[] args) { MyObject test = new MyObject(); test.Properties = new Dictionary() { { "int", 15 }, { "string", "hi" }, { "number", 7 } }; Print("Original:", test); string json = JsonConvert.SerializeObject(test); Console.WriteLine("JSON:\n{0}\n", json); MyObject parsed = JsonConvert.DeserializeObject(json); Print("Deserialized:", parsed); } private static void Print(string heading, MyObject obj) { Console.WriteLine(heading); foreach (var kvp in obj.Properties) Console.WriteLine("{0} = {1} of {2}", kvp.Key, kvp.Value, kvp.Value.GetType().Name); Console.WriteLine(); } } 

没有转换器,结果将是:

 Deserialized: int = 15 of Int64 string = hi of String number = 7 of Int64 

并使用转换器:

 Deserialized: int = 15 of Int32 string = hi of String number = 7 of Int32 

我接受了Enzi的回答,因为这是我要求的。

但是,从那以后我改变了我的策略。

现在我正在反序列化到ChangeSet ,而不是字典有一个带有更改的强类型Entity (T)对象。 它还有一个List ,其中包含传入json中存在的属性的属性名称。 然后,我使用自定义MediaFormatter在反序列化期间填充该列表。 这样我得到一个强类型对象并正确反序列化所有属性,我从列表中知道当我想要进行批量操作时,我应该在我的T集合上设置哪些属性。

这样我基本上将我的实体用作DTO,而不必为不同的批处理操作提供无数不同的DTO。 如果我自己这么说的话,我会很漂亮。 🙂

尝试

  var variable = Convert.ToInt32(object) 

迭代Dictionary一次并使用此Int32重写其object ,或者每次读取object时执行Int32转换。

这对我很有用:

 public class ParseNumbersAsInt32Converter : JsonConverter { public override bool CanConvert(Type objectType) { return objectType == typeof(long) || objectType == typeof(long?) || objectType == typeof(object); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { serializer.Serialize(writer, value); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (reader.Value != null && reader.Value is long) { return Convert.ToInt32(reader.Value); } return reader.Value; } }