我如何在json反序列化期间忽略未知的枚举值?
当我的枚举与json属性中提供的字符串值不匹配时,如何使Json.net不抛出?
当我根据当前文档创建枚举时会发生这种情况,但是第三方API稍后会添加更多的枚举值。
我很高兴将特殊值标记为Unknown或使用可为空的枚举,并且不匹配的值将返回null。
回答:
您可以使用custom解决此问题JsonConverter
。这是我使用StringEnumConverter
来自Json.Net
的类中的一些片段组合而成的。它应该使您能够灵活地以各种方式处理事情。运作方式如下:
- 如果在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: SetNonNullableStatusWithValidIntValue: 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)
以上是 我如何在json反序列化期间忽略未知的枚举值? 的全部内容, 来源链接: utcz.com/qa/403904.html