当我的枚举与json属性中提供的字符串值不匹配时,如何让Json.net不要抛出?
当我基于当前文档创建枚举时,会发生这种情况,但第三方API稍后会添加更多枚举值.
我会很高兴将特殊值标记为未知或使用可空的枚举,而不匹配的值将返回null.
解决方法
您可以使用自定义JsonConverter解决此问题.这是一个我使用来自Json.Net的StringEnumConverter类中的几个集合.它应该给你灵活的处理事情,无论你决定什么.以下是它的工作原理:
>如果JSON中找到的值与枚举(作为字符串或整数)匹配,则使用该值. (如果值是整数,并且有多个可能的匹配,则使用第一个匹配项.)
>否则,如果枚举类型为空,则将该值设置为null.
>否则,如果枚举有一个名为“未知”的值,那么使用该值.
>否则使用枚举的第一个值.
如果你不喜欢规则的工作方式,或者想要简化它,那么请自由.以下是代码:
class TolerantEnumConverter : JsonConverter { public override bool CanConvert(Type objectType) { Type type = IsNullableType(objectType) ? Nullable.GetUnderlyingType(objectType) : objectType; return type.IsEnum; } public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer) { bool isNullable = IsNullableType(objectType); Type enumType = isNullable ? Nullable.GetUnderlyingType(objectType) : objectType; string[] names = Enum.GetNames(enumType); if (reader.TokenType == JsonToken.String) { string enumText = reader.Value.ToString(); if (!string.IsNullOrEmpty(enumText)) { string match = names .Where(n => string.Equals(n,enumText,StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); if (match != null) { return Enum.Parse(enumType,match); } } } else if (reader.TokenType == JsonToken.Integer) { int enumVal = Convert.ToInt32(reader.Value); int[] values = (int[])Enum.GetValues(enumType); if (values.Contains(enumVal)) { return Enum.Parse(enumType,enumVal.ToString()); } } if (!isNullable) { string defaultName = names .Where(n => string.Equals(n,"Unknown",StringComparison.OrdinalIgnoreCase)) .FirstOrDefault(); if (defaultName == null) { defaultName = names.First(); } return Enum.Parse(enumType,defaultName); } return null; } public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer) { writer.WriteValue(value.ToString()); } private bool IsNullableType(Type t) { return (t.IsGenericType && t.GetGenericTypeDefinition() == typeof(Nullable<>)); } }
这是一个演示,它使转换器使用几个不同的枚举(一个有一个“未知”值,而另一个不):
[JsonConverter(typeof(TolerantEnumConverter))] enum Status { Ready = 1,Set = 2,Go = 3 } [JsonConverter(typeof(TolerantEnumConverter))] enum Color { Red = 1,Yellow = 2,Green = 3,Unknown = 99 } class Foo { public Status NonNullableStatusWithValidStringValue { get; set; } public Status NonNullableStatusWithValidIntValue { get; set; } public Status NonNullableStatusWithInvalidStringValue { get; set; } public Status NonNullableStatusWithInvalidIntValue { get; set; } public Status NonNullableStatusWithNullValue { get; set; } public Status? NullableStatusWithValidStringValue { get; set; } public Status? NullableStatusWithValidIntValue { get; set; } public Status? NullableStatusWithInvalidStringValue { get; set; } public Status? NullableStatusWithInvalidIntValue { get; set; } public Status? NullableStatusWithNullValue { get; set; } public Color NonNullableColorWithValidStringValue { get; set; } public Color NonNullableColorWithValidIntValue { get; set; } public Color NonNullableColorWithInvalidStringValue { get; set; } public Color NonNullableColorWithInvalidIntValue { get; set; } public Color NonNullableColorWithNullValue { get; set; } public Color? NullableColorWithValidStringValue { get; set; } public Color? NullableColorWithValidIntValue { get; set; } public Color? NullableColorWithInvalidStringValue { get; set; } public Color? NullableColorWithInvalidIntValue { get; set; } public Color? NullableColorWithNullValue { get; set; } } class Program { static void Main(string[] args) { string json = @" { ""NonNullableStatusWithValidStringValue"" : ""Set"",""NonNullableStatusWithValidIntValue"" : 2,""NonNullableStatusWithInvalidStringValue"" : ""Blah"",""NonNullableStatusWithInvalidIntValue"" : 9,""NonNullableStatusWithNullValue"" : null,""NullableStatusWithValidStringValue"" : ""Go"",""NullableStatusWithValidIntValue"" : 3,""NullableStatusWithNullValue"" : null,""NullableStatusWithInvalidStringValue"" : ""Blah"",""NullableStatusWithInvalidIntValue"" : 9,""NonNullableColorWithValidStringValue"" : ""Green"",""NonNullableColorWithValidIntValue"" : 3,""NonNullableColorWithInvalidStringValue"" : ""Blah"",""NonNullableColorWithInvalidIntValue"" : 0,""NonNullableColorWithNullValue"" : null,""NullableColorWithValidStringValue"" : ""Yellow"",""NullableColorWithValidIntValue"" : 2,""NullableColorWithNullValue"" : null,""NullableColorWithInvalidStringValue"" : ""Blah"",""NullableColorWithInvalidIntValue"" : 0,}"; Foo foo = JsonConvert.DeserializeObject<Foo>(json); foreach (PropertyInfo prop in typeof(Foo).GetProperties()) { object val = prop.GetValue(foo,null); Console.WriteLine(prop.Name + ": " + (val == null ? "(null)" : val.ToString())); } } }
输出:
NonNullableStatusWithValidStringValue: Set NonNullableStatusWithValidIntValue: Set NonNullableStatusWithInvalidStringValue: Ready NonNullableStatusWithInvalidIntValue: Ready NonNullableStatusWithNullValue: Ready NullableStatusWithValidStringValue: Go NullableStatusWithValidIntValue: Go NullableStatusWithInvalidStringValue: (null) NullableStatusWithInvalidIntValue: (null) NullableStatusWithNullValue: (null) NonNullableColorWithValidStringValue: Green NonNullableColorWithValidIntValue: Green NonNullableColorWithInvalidStringValue: Unknown NonNullableColorWithInvalidIntValue: Unknown NonNullableColorWithNullValue: Unknown NullableColorWithValidStringValue: Yellow NullableColorWithValidIntValue: Yellow NullableColorWithInvalidStringValue: (null) NullableColorWithInvalidIntValue: (null) NullableColorWithNullValue: (null)