Как получить newtonsoft для десериализации да и нет для boolean

ПРИМЕЧАНИЕ. Я предоставил решение в нижней части этого фида.

У меня есть приложение С# Win 8, где я де-сериализую некоторый json, который выглядит так:

"{'Unit':[{'name':'House 123',isAvailable:'no'},{'name':'House 456',isAvailable:'yes'}]}"
into a class that uses this interface:
 public interface IUnit
 {
 string Name { get; }
 bool isAvailable { get; }
 }

Но Newtonsoft выдает ошибку:

Неожиданный символ, встречающийся при разборе значения: n. Дорожка 'Unit [0].isAvailable, строка 1, позиция 42.

Есть ли способ расширить Newtonsoft для анализа да/нет или 1/0 на основе результирующего свойства свойства объекта bool? Сейчас он работает только для true/false.

В пользовательских конвертерах для нескольких классов есть несколько сообщений, но не примитивный тип типа bool.

Любые предложения?

5 ответов

//Это то, что я придумал...

using System;
 using System.Collections.Generic;
 using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace NewtonTest
{
internal class NewtonTest
{
 public class Data
 {
 public IEnumerable<iunit> Unit { get; set; }
 public override string ToString()
 {
 return string.Format("Data{{Unit=[{0}]}}",
 string.Join(", ", Unit.Select(c =>
 string.Format("{0} - Single Unit: {1}", 
 c.Name,
 c.isSingleUnit.ToString()))));
 }
 }
 public interface IUnit
 {
 string Name { get; }
 // [JsonConverter(typeof(Converter))]
 bool isSingleUnit { get; }
 }
 public class House : IUnit
 {
 public House(string name, bool isSingle)
 {
 this.Name = name;
 this.isSingleUnit = isSingle;
 }
 public string Name { get; private set; }
 public bool isSingleUnit { get; private set; }
 }
 public class Apartment : IUnit
 {
 public Apartment(string name, bool isSingle)
 {
 this.Name = name;
 this.isSingleUnit = isSingle;
 }
 public string Name { get; private set; }
 public bool isSingleUnit { get; private set; }
 }
 private static bool ConvertToBool(string value)
 {
 value =
 value.ToUpper().
 Replace("YES", "TRUE").
 Replace("Y", "TRUE").
 Replace("1", "TRUE").
 Replace("NO", "FALSE").
 Replace("N", "FALSE").
 Replace("0", "FALSE");
 bool result = false;
 bool.TryParse(value, out result);
 return result;
 }
 private class UnitConverter : Newtonsoft.Json.JsonConverter
 {
 public override bool CanConvert(Type objectType)
 {
 return typeof (NewtonTest.IUnit).IsAssignableFrom(objectType);
 }
 public override object ReadJson(Newtonsoft.Json.JsonReader reader, Type objectType, object existingValue,
 Newtonsoft.Json.JsonSerializer serializer)
 {
 JObject obj = serializer.Deserialize<jtoken>(reader) as JObject;
 if (obj != null)
 {
 string result = obj["isSingleUnit"].ToObject<string>();
 bool isSingleUnit = ConvertToBool(result);
 string name = obj["name"].ToObject<string>();
 if (isSingleUnit)
 {
 return new NewtonTest.House(name, isSingleUnit);
 }
 else
 {
 return new NewtonTest.Apartment(name, isSingleUnit);
 }
 }
 else
 {
 return null;
 }
 }
 public override void WriteJson(Newtonsoft.Json.JsonWriter writer, object value,
 Newtonsoft.Json.JsonSerializer serializer)
 {
 throw new NotImplementedException();
 }
 }
 public static void Main()
 {
 Newtonsoft.Json.JsonSerializer serializer = new Newtonsoft.Json.JsonSerializer();
 serializer.Converters.Add(new UnitConverter());
 string json =
 "{'Unit':[{'name':'Apartment 123',isSingleUnit:'no'},{'name':'House 456',isSingleUnit:'yes'}]}".Replace(
 '\'', '\"');
 var obj = serializer.Deserialize(new StringReader(json), typeof (Data));
 Console.WriteLine(obj);
 Console.ReadKey();
 }
}
}
</string></string></jtoken></iunit>


public class MyBooleanConverter : JsonConverter
{
 public override bool CanWrite { get { return false; } }
 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 {
 throw new NotImplementedException();
 }
 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
 {
 var value = reader.Value;
 if (value == null || String.IsNullOrWhiteSpace(value.ToString()))
 {
 return false;
 }
 if ("yes".Equals(value, StringComparison.OrdinalIgnoreCase))
 {
 return true;
 }
 return false;
 }
 public override bool CanConvert(Type objectType)
 {
 if (objectType == typeof(String) || objectType == typeof(Boolean))
 {
 return true;
 }
 return false;
 }
}
public interface IUnit
{
 string Name { get; }
 [JsonConverter(typeof(MyBooleanConverter))]
 bool isAvailable { get; }
}


я предлагаю этот подход

using System;
using Newtonsoft.Json;
namespace JsonConverters
{
 public class BooleanJsonConverter : JsonConverter
 {
 public override bool CanConvert( Type objectType )
 {
 return objectType == typeof( bool );
 }
 public override object ReadJson( JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer )
 {
 switch ( reader.Value.ToString().ToLower().Trim() )
 {
 case "true":
 case "yes":
 case "y":
 case "1":
 return true;
 case "false":
 case "no":
 case "n":
 case "0":
 return false;
 }
 // If we reach here, we're pretty much going to throw an error so let let Json.NET throw it pretty-fied error message.
 return new JsonSerializer().Deserialize( reader, objectType );
 }
 public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer )
 {
 }
 }
}


Вот что я придумал.

public class JsonBooleanConverter : JsonConverter
{
 public override bool CanWrite { get { return false; } }
 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
 {
 throw new NotImplementedException();
 }
 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
 {
 var value = reader.Value.ToString().ToLower().Trim();
 switch (value)
 {
 case "true":
 case "yes":
 case "y":
 case "1":
 return true;
 }
 return false;
 }
 public override bool CanConvert(Type objectType)
 {
 if (objectType == typeof(Boolean))
 {
 return true;
 }
 return false;
 }
}

Использование:

var myObj = JsonConvert.DeserializeObject<t>(json, new JsonBooleanConverter());
</t>


Здесь версия решения @John в vb для тех, кому это нужно. Он обрабатывает Boolean и nullable Boolean. On Write it преобразует в 0/1, чтобы сохранить некоторые байты в передаче (а не true/false):

Imports Newtonsoft.Json
Public Class MyBooleanConverter
 Inherits JsonConverter
Public Overrides ReadOnly Property CanWrite As Boolean
 Get
 Return True
 End Get
End Property
Public Overrides Sub WriteJson(writer As JsonWriter, value As Object, serializer As JsonSerializer)
 Dim boolVal As Boolean = value
 writer.WriteValue(If(boolVal, 1, 0))
End Sub
Public Overrides Function ReadJson(reader As JsonReader, objectType As Type, existingValue As Object, serializer As JsonSerializer) As Object
 Dim value = reader.Value
 If IsNothing(value) OrElse String.IsNullOrWhiteSpace(value.ToString()) OrElse "0" = value Then
 Return False
 End If
 If 0 = String.Compare("yes", value, True) OrElse 0 = String.Compare("true", value, True) Then
 Return True
 End If
 Return False
End Function
Public Overrides Function CanConvert(objectType As Type) As Boolean
 Return objectType = GetType(Boolean) OrElse objectType = GetType(Boolean?) 'OrElse objectType = GetType(String)
End Function
End Class

licensed under cc by-sa 3.0 with attribution.