2013-07-19 19 views
6

Tôi có một số mã .NET để deserializes JSON các đối tượng được tạo bởi một webservice chạy ngôn ngữ động. Bởi vì nguồn là động, đôi khi nó nối tiếp các giá trị tích phân trong định dạng float (e. G. 2 được tuần tự hóa thành "2.0").Làm thế nào tôi có thể khôi phục hành vi intererization int sau khi nâng cấp Json.NET?

Với Json.NET 4.0.4, điều này làm việc liền mạch (có vẻ như làm tròn được áp dụng khi deserializing). Với việc nâng cấp lên Json.NET 4.5, mặc dù, deserializing 2.0 hiện ném một số FormatException. Đây là mã:

// 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)); 

Có cách nào dễ dàng để khôi phục lại hành vi gốc không? Hành vi lý tưởng sẽ chỉ là deserialize số với giá trị tích phân, nhưng ở bất kỳ định dạng nào (e. G. 2.0, 1e10, nhưng không phải 2.5), nhưng tôi sẽ giải quyết cho hành vi 4.0.4.

Trả lời

6

Bạn có thể thực hiện việc này bằng cách thực hiện một tùy chỉnh JsonConverter sẽ xử lý làm tròn (hoặc hủy bỏ) các giá trị thập phân. Nó có thể giống như thế này:

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(); 
    } 
} 

Sau đó, bạn có thể sử dụng bộ chuyển đổi tùy chỉnh như thế này:

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); 
} 

Sản lượng của các bên trên sẽ là:

3 
0 
4 
5 
-3 
-2 

Nếu bạn sẽ thay vì công cụ chuyển đổi bỏ qua các giá trị thập phân thay vì làm tròn chúng, hãy thay thế dòng mã sau đây

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

với điều này:

 return (existingValue ?? default(int)); 

Sau khi thực hiện sự thay đổi đó, đầu ra của mã kiểm tra phía trên sau đó sẽ trông như thế này:

0 
0 
0 
5 
-3 
0 
+0

Có thể cần phải cân nhắc việc thêm 'objectType == typeof (object) 'trong' CanConvert', nếu lớp đích "không chỉ định" loại thực tế, ví dụ 'class MyObject {đối tượng công cộng Id; } ' – drzaus

+0

@drzaus Có thể, nhưng hãy cẩn thận. Nếu bạn làm điều đó và bạn có bất kỳ thuộc tính khác của loại 'đối tượng' là * không * số, bộ chuyển đổi này sẽ cố gắng xử lý chúng, mà có thể không phải là những gì bạn đang mong đợi. Bạn sẽ phải thêm mã để xử lý trường hợp đó. –

+0

Ah phải, tôi đã nghĩ đến một số [câu trả lời khác] (http://stackoverflow.com/a/28748973/1037948) mà xử lý nó bằng cách kiểm tra 'JTokenType' và nếu nó không phải là một kiểu dự kiến, thay vì ném một' FormatException' chỉ trả về 'serializer.Deserialize (reader)', mà dường như ủy quyền nó cho bất cứ điều gì khác nên xử lý nó một cách thích hợp. Nó đã làm việc cho đến nay trong các thử nghiệm của tôi với các loại lồng nhau, phức tạp. – drzaus

Các vấn đề liên quan