如何让newtonsoft反序列化yes和no to boolean

Cod*_*ops 11 c# serialization class extend json.net

注意:我已在此Feed的底部提供了解决方案.

我有一个C#Win 8应用程序,我正在反序列化一些看起来像这样的json:

{
    'Unit': [
        {
            'name':'House 123',
            isAvailable:'no'
        },
        {
            'name':'House 456',
            isAvailable:'yes'
        }]
}
Run Code Online (Sandbox Code Playgroud)

进入使用此接口的类:

public interface IUnit
{
    string Name { get; }
    bool isAvailable { get; }
}
Run Code Online (Sandbox Code Playgroud)

但是牛顿软件会抛出一个错误:

解析值时遇到意外的字符:n.Path'Unit [0] .isAvailable,第1行,第42位.

有没有办法根据生成的对象属性类型bool扩展Newtonsoft来解析yes/no或1/0?现在它只适用于真/假.

关于类的自定义转换器有几个帖子,但不是像bool这样的原始类型.

有什么建议?

Cra*_*ntz 17

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; }
}
Run Code Online (Sandbox Code Playgroud)


har*_*shr 7

我会建议这种方法

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

    }
}
Run Code Online (Sandbox Code Playgroud)


Pet*_*ete 5

这就是我想出的。

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

var myObj = JsonConvert.DeserializeObject<T>(json, new JsonBooleanConverter());
Run Code Online (Sandbox Code Playgroud)

  • 是的,对于您精心设计的特定测试用例来说确实如此。试试这个:用两个调用替换 `main()` 函数中的所有内容:`JsonConvert.DeserializeObject&lt;bool&gt;("true", new JsonBooleanConverter()); JsonConvert.DeserializeObject&lt;bool&gt;("yes", new JsonBooleanConverter());` 第一个将成功,后者将失败,并出现以下异常: `{"解析值时遇到意外字符:y.Path '',第 0 行,位置 0。"}`。这是因为您误用了 Converter:它不是格式错误的 JSON 的预解析修复机制,而这正是这里使用它的方式。 (2认同)

Cod*_*ops 1

//这就是我想出的...

   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();
    }
}
}
Run Code Online (Sandbox Code Playgroud)