如何让newtonsoft将yes和no反序列化为布尔值
Posted
技术标签:
【中文标题】如何让newtonsoft将yes和no反序列化为布尔值【英文标题】:how to get newtonsoft to deserialize yes and no to boolean 【发布时间】:2013-01-09 14:03:40 【问题描述】:注意:我已在此提要底部提供了解决方案。
我有一个 C# Win 8 应用程序,我正在反序列化一些看起来像这样的 json:
'Unit': [
'name':'House 123',
isAvailable:'no'
,
'name':'House 456',
isAvailable:'yes'
]
进入使用此接口的类:
public interface IUnit
string Name get;
bool isAvailable get;
但是 Newtonsoft 抛出错误:
解析值时遇到意外字符:n。小路 'Unit[0].isAvailable,第 1 行,第 42 位。
有没有办法扩展 Newtonsoft 以根据结果对象属性类型 bool 解析 yes/no 或 1/0?现在它只适用于真/假。
有几篇关于类的自定义转换器的帖子,但不是像 bool 这样的原始类型。
有什么建议吗?
【问题讨论】:
【参考方案1】:这是@John 在 vb 中的解决方案的一个版本,供任何需要的人使用。它处理布尔值和可为空的布尔值。在写入时它转换为 0/1 以节省传输中的一些字节(而不是真/假):
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
【讨论】:
【参考方案2】:这是我想出来的。
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());
【讨论】:
这确实有效。 github.com/petekapakos/JsonBooleanConverterTest 是的,它确实适用于您精心设计的特定测试用例。试试这个:用两个调用替换main()
函数中的所有内容:JsonConvert.DeserializeObject<bool>("true", new JsonBooleanConverter()); JsonConvert.DeserializeObject<bool>("yes", new JsonBooleanConverter());
第一个会成功,后者会失败,并出现以下异常:"Unexpected character encountered while parsing value: y. Path '', line 0, position 0."
。这是因为您误用了 Converter:它不是格式错误 JSON 的预解析修复机制,这就是它在此处使用的方式。【参考方案3】:
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;
【讨论】:
感谢克雷格的快速响应。这看起来比我想出的解决方案更好,但我在让它与我的代码一起工作时遇到问题:我已将其发布在下一个答案中...... Newtonsoft.Json.JsonSerializer 序列化器 = new Newtonsoft.Json.JsonSerializer(); serializer.Converters.Add(new MyBooleanConverter()) string json = "'Unit':['name':'Apartment 123',isSingleUnit:'no','name':'House 456',isSingleUnit: 'yes']".Replace('\'', '\"'); var obj = serializer.Deserialize(new StringReader(json), typeof(bool)); Console.WriteLine(obj); 它只是返回“假”。 基础知识+1;不过,您的代码可能会被严重削减:) 考虑这个:***.com/a/809558/820068 然后考虑将比较改为:"if ("yes".Equals(value.ToString() ..."【参考方案4】:我建议this approach
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 )
【讨论】:
【参考方案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("DataUnit=[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();
【讨论】:
我看不出你在哪里告诉反序列化器你期望IUnit
。它不会知道应用正确的转换器。
抱歉,代码嵌套的方式很难阅读。它在这个方法中: public override bool CanConvert(Type objectType) return typeof (NewtonTest.IUnit).IsAssignableFrom(objectType);
不够。您需要在 Main()
中引用 IUnit
。以上是关于如何让newtonsoft将yes和no反序列化为布尔值的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 NewtonSoft Json.Net 将 Json 字典反序列化为平面类
Newtonsoft Json 将字典反序列化为来自 DataContractJsonSerializer 的键/值列表
csharp 使用Newtonsoft JSON.NET将任何对象序列化/反序列化为JSON
使用 Newtonsoft 将 JSON 反序列化为 .NET 对象(或者可能是 LINQ to JSON?)