2013-07-19 28 views
6

我有一些.NET代码反序列化JSON由运行动态语言的webservice创建的对象。因为源是动态的,所以它有时以浮点格式序列化整数值(例如,2被序列化为“2.0”)。如何在升级Json.NET后恢复int反序列化行为?

Json.NET 4.0.4,这无缝工作(似乎舍入被应用时反序列化)。但是,升级到Json.NET 4.5后,反序列化2.0现在会抛出FormatException。这里的代码:

// works as expected in both versions 
var s = "2"; 
Console.WriteLine(JsonConvert.DeserializeObject<int>(s)); 

// throws FormatException in 4.5 only 
var s = "2.0"; 
Console.WriteLine(JsonConvert.DeserializeObject<int>(s)); 

// throws FormatException in 4.5, rounds to 3 in 4.0.4 
var s = "2.6"; 
Console.WriteLine(JsonConvert.DeserializeObject<int>(s)); 

有没有简单的方法来恢复原来的行为?理想的行为将是仅对具有整数值的数字进行反序列化,但是以任何格式(例如2.0,1e10,但不是2.5),但我会解决4.0.4行为。

回答

6

您可以通过自定义JsonConverter来处理小数值的舍入(或丢弃)。它可能是这个样子:

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

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     JValue jsonValue = serializer.Deserialize<JValue>(reader); 

     if (jsonValue.Type == JTokenType.Float) 
     { 
      return (int)Math.Round(jsonValue.Value<double>()); 
     } 
     else if (jsonValue.Type == JTokenType.Integer) 
     { 
      return jsonValue.Value<int>(); 
     } 

     throw new FormatException(); 
    } 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
} 

然后,您可以使用自定义转换器是这样的:

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    Converters = new List<JsonConverter> { new CustomIntConverter() } 
}; 

string json = @"[2.6, 0, 4.1, 5, -3, -2.2]"; 

List<int> list = JsonConvert.DeserializeObject<List<int>>(json, settings); 

foreach (int val in list) 
{ 
    Console.WriteLine(val); 
} 

的上面的输出会是这样:

3 
0 
4 
5 
-3 
-2 

,如果您而是转换器忽略十进制值而不是四舍五入,替换以下代码行

 return (int)Math.Round(jsonValue.Value<double>()); 

与此:

 return (existingValue ?? default(int)); 

做出这样的转变后,上面的测试代码的输出会再看看这样的:

0 
0 
0 
5 
-3 
0 
+0

可能需要考虑增加'的objectType == typeof运算(对象)'CanConvert'中,如果目标类“没有指定”实际类型,例如'class MyObject {public object Id; }' – drzaus

+0

@drzaus也许,但要小心。如果你这样做,并且你有任何其他'object'类型的属性都是* not *数字,那么这个转换器将会尝试处理它们,这可能不是你所期待的。你必须添加代码来处理这种情况。 –

+0

对啊,我正在考虑一些[其他答案](http://stackoverflow.com/a/28748973/1037948),它通过检查JTokenType来处理它,如果它不是预期的类型,而不是抛出' FormatException'只返回'serializer.Deserialize(reader)',它似乎将它委托给其他任何应该适当处理它的东西。它在我的测试中工作到目前为止,嵌套的复杂类型。 – drzaus