2013-07-19 61 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