2011-10-18 29 views
7

Hầu hết các trình phân tích cú pháp Json không tuần tự hóa NaN, bởi vì trong Javascript, NaN không phải là hằng số. Json.Net, tuy nhiên, không tuần tự hóa các giá trị NaN vào NaN, có nghĩa là nó xuất ra Json không hợp lệ; cố gắng để deserialize Json này sẽ thất bại với hầu hết các trình phân tích cú pháp. (Chúng tôi đang deserializing trong WebKit.)Các giá trị NaN tuần tự hóa thành JSON dưới dạng null trong JSON.NET

Chúng tôi đã hack mã Json.Net để sản lượng giá trị null khi thông qua NaN, nhưng điều này có vẻ như một giải pháp kém. Douglas Crockford (một lần) khuyến cáo sử dụng null ở vị trí của Nans:

http://www.json.org/json.ppt (Nhìn vào slide 16)

Rõ ràng điều này sẽ không làm việc trong mọi trường hợp, nhưng nó sẽ là ok cho các mục đích của chúng tôi. Chúng tôi không muốn thay đổi mã nguồn của Json.Net. Có ai biết làm thế nào để sử dụng Json.Net để chuyển đổi đầu vào NaN vào đầu ra null?

Trả lời

8

Tác giả advises us để “Viết JsonConverter cho phao/đôi để làm NaN an toàn nếu điều này là quan trọng đối với bạn”, vì vậy đó là những gì bạn có thể làm:

class LawAbidingFloatConverter : JsonConverter { 
    public override bool CanRead 
    { 
     get 
     { 
      return false; 
     } 
    } 
    public override bool CanWrite 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     var val = value as double? ?? (double?) (value as float?); 
     if (val == null || Double.IsNaN((double)val) || Double.IsInfinity((double)val)) 
     { 
      writer.WriteNull(); 
      return; 
     } 
     writer.WriteValue((double)val); 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(double) || objectType == typeof(float); 
    } 
} 

và sau đó sử dụng nó:

var settings = new JsonSerializerSettings(); 
var floatConverter = new LawAbidingFloatConverter(); 
settings.Converters.Add(floatConverter); 
var myConverter = new JsonNetSerializer(settings); 
+2

Không làm việc cho 'double' ** VÀ ** 'float' -' như đôi 'là ** luôn **' null'?! –

+1

Bạn nói đúng, nó không hoạt động với 'float'. Tôi không chắc chắn lý do tại sao '(double?) Value' mang lại' null' khi giá trị là một float nhưng giá trị '(double?) (Float?)' là ok. Tôi đã cập nhật câu trả lời của mình bằng giải pháp làm việc. Cảm ơn! –

4

Raphael Schweikerts giải pháp với float hỗ trợ:

public class StandardFloatConverter : JsonConverter 
{ 
    public override bool CanRead 
    { 
     get 
     { 
      return false; 
     } 
    } 
    public override bool CanWrite 
    { 
     get 
     { 
      return true; 
     } 
    } 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     if (value == null) 
     { 
      writer.WriteNull(); 
      return; 
     } 

     var val = Convert.ToDouble(value); 
     if(Double.IsNaN(val) || Double.IsInfinity(val)) 
     { 
      writer.WriteNull(); 
      return; 
     } 
     // Preserve the type, otherwise values such as 3.14f may suddenly be 
     // printed as 3.1400001049041748. 
     if (value is float) 
      writer.WriteValue((float)value); 
     else 
      writer.WriteValue((double)value); 
    } 
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException(); 
    } 
    public override bool CanConvert(Type objectType) 
    { 
     return objectType == typeof(double) || objectType == typeof(float); 
    } 
} 
+1

Nếu duy trì hành vi ban đầu cho các giá trị bình thường là quan trọng, ta cũng có thể thay thế 'write.WriteValue (val)' bằng 'if (value float) writer.WriteValue ((float) val); else writer.WriteValue ((double) val) '. Nếu không, đột nhiên '3.14f' có thể được tuần tự hóa là' 3.1400001049041748' thay vì '3.14'. Điều này đã phá vỡ một trong những đơn vị kiểm tra trong ứng dụng của tôi. –

+0

Cảm ơn bạn đã chỉ ra điều này nhưng tôi không thể chấp nhận chỉnh sửa của bạn nữa (đã bị từ chối!?) ... Tôi đã thay đổi câu trả lời theo chỉnh sửa của bạn. –

2

Vì lợi ích của độc giả trong tương lai, nếu số không được chấp nhận cho bạn thay vì số không, có vẻ như vấn đề này đã được giải quyết bằng Json.Net.

Serializing NaN và Infinity Floating Point Values ​​

Json.NET không còn serializes NaN và dương vô cực và tiêu cực giá trị dấu chấm động như biểu tượng, đó là JSON không hợp lệ. Với 5.0, mặc định mới là sắp xếp lại các giá trị đó dưới dạng chuỗi, ví dụ: "NaN" thay vì NaN. Không có thay đổi để tuần tự hóa các số dấu phẩy động bình thường .

Cài đặt FloatFormatHandling đã được thêm vào để bạn có thể kiểm soát cách các giá trị NaN và vô hạn được đăng.

string json;  
IList<double> d = new List<double> {1.1, double.NaN, double.PositiveInfinity}; 

json = JsonConvert.SerializeObject(d); 

// [1.1,"NaN","Infinity"] 

json = JsonConvert.SerializeObject(d, new JsonSerializerSettings {FloatFormatHandling = FloatFormatHandling.Symbol}); 

// [1.1,NaN,Infinity] 

json = JsonConvert.SerializeObject(d, new JsonSerializerSettings {FloatFormatHandling = FloatFormatHandling.DefaultValue}); 

// [1.1,0.0,0.0] 
Các vấn đề liên quan