visual variable valor una toboolean tipo que metodo hacer declarar datos dato convert como booleano booleana c# class serialization extend json.net

c# - variable - cómo hacer que newtonsoft deserialice sí y no a booleano



tipo de dato booleano c# (5)

NOTA: He proporcionado la solución en la parte inferior de este feed.

Tengo una aplicación C # Win 8 donde estoy serializando un json que se ve así:

"{''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; } }

Pero Newtonsoft arroja un error:

Carácter inesperado encontrado al analizar el valor: n. Ruta ''Unidad [0] .isDisponible, línea 1, posición 42.

¿Hay alguna manera de extender Newtonsoft para analizar sí / no o 1/0 en función del tipo de propiedad de objeto resultante de bool? En este momento solo funciona para verdadero / falso.

Hay varias publicaciones sobre convertidores personalizados para clases, pero no de tipo primitivo como bool.

¿Alguna sugerencia?


// Esto es lo que se me ocurrió ...

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


Sugeriría este enfoque

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''s let Json.NET throw it''s pretty-fied error message. return new JsonSerializer().Deserialize( reader, objectType ); } public override void WriteJson( JsonWriter writer, object value, JsonSerializer serializer ) { } } }


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


Esto es lo que se me ocurrió.

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

Uso:

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


Aquí hay una versión de la solución de @John en vb para cualquiera que lo necesite. Maneja Boolean Boolean y Boolean Nullable. En Escribir lo convierte en 0/1 para guardar algunos bytes en la transferencia (en lugar de verdadero / falso):

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