我怎么可以忽略JSON反序列化过程中未知的枚举值? [英] How can I ignore unknown enum values during json deserialization?

查看:489
本文介绍了我怎么可以忽略JSON反序列化过程中未知的枚举值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何才能Json.net不要扔了,当我的枚举不匹配JSON酒店所提供的字符串值?

How can I get Json.net not to throw up when my enum doesn't match string value provided in the json property?

这发生在我创建枚举根据目前的资料,但第三方API之后增加了更多的枚举值。

This happens when I create enum based on current documentation, but the third party API adds more enum values later.

我会很乐意与任何标记的特殊价值,未知或使用可空枚举和无与伦比的价值将返回null。

I would be happy with either marking special value as Unknown or using a nullable enum and unmatched value would return null.

推荐答案

您可以解决这个问题,一个自定义的 JsonConverter 。这是一个我放在一起利用来自Json.Net的 StringEnumConverter 类几块。它应该给你的灵活性来处理你决定什么办法的事情。下面是它如何工作的:

You can solve this problem with a custom JsonConverter. Here is one I put together using a few pieces from the StringEnumConverter class that comes from Json.Net. It should give you the flexibility to handle things whatever way you decide. Here's how it works:


  • 如果在JSON中找到的值的枚举匹配(无论是作为一个字符串或整数),该值用过的。 (如果值为整数,存在多个可能的匹配,其中第一个被使用。)

  • 否则,如果枚举类型可以为空,则该值设置为null。

  • 否则,如果枚举有一个名为未知的值,则使用该值。

  • 否则,枚举的第一个值被使用。

  • If the value found in the JSON matches the enum (either as a string or an integer), that value is used. (If the value is integer and there are multiple possible matches, the first of those is used.)
  • Otherwise if the enum type is nullable, then the value is set to null.
  • Otherwise if the enum has a value called "Unknown", then that value is used.
  • Otherwise the first value of the enum is used.

如果你不喜欢规则的工作方式,或者希望简化它,感觉自由。下面的代码:

If you don't like the way the rules work, or want to simplify it, feel free. Here's the code:

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

下面是把它转换器通过其演示

Here is a demo which puts it the converter through its paces using a couple of different enums (one has an "Unknown" value, and the other does not):

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



输出:

Output:

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)

这篇关于我怎么可以忽略JSON反序列化过程中未知的枚举值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆