簡體   English   中英

JSON.NET-反序列化時的自定義枚舉處理

[英]JSON.NET - custom enum handling at deserialization

我們有一個JSON,可以將其反序列化為自定義域模型,一點問題都沒有。 它包含一個作為自定義枚舉的屬性:

public enum UserType
{
    President,
    Chump
}

現在,我們更改了枚舉類,但仍然需要接受並反序列化到達的任何JSON的先前值。 就像我們現在有兩個版本的JSON

public enum UserType
{
    President,
    Vice-President,
    Citizen  // Chump maps to Citizen, now.
}

以及json本身。

"userType": "chump"; // needs to map to Citizen

我不確定該怎么做。

這是使用JsonConverter嗎?

同樣,這是我們用於所有序列化和反序列化的自定義設置。 注意:我們將任何枚舉序列化為其string描述/值,而不是其int值。

internal static JsonSerializerSettings JsonSerializerSettings => new JsonSerializerSettings
{
    Converters = new JsonConverter[]
    {
        new StringEnumConverter()
    },
    Formatting = Formatting.Indented
};

干杯!

在您的Enum只需添加EnumMember屬性,該屬性指定序列化/反序列化過程的值。

public enum UserType
{
    President,
    VicePresident,

    [EnumMember(Value = "chump")]
    Citizen  // Chump maps to Citizen, now.
}

該物業userType將是Citizen的時候,在你的JSON,在userType屬性等於"Chump""Citizen"

請記住將System.Runtime.Serialization引用添加到您的項目。

編輯

我注意到對EnumMember屬性的Value屬性的檢查區分大小寫。 因此,如果在json中有"chump"則不能使用"Chump" "chump" 要解決此問題,可以使用自定義StringEnumConverter

public class UserTypeEnumConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        var userTypeType = typeof(UserType);
        if (objectType == userTypeType)
        {
            var value = reader.Value.ToString().ToLower();

            foreach (var item in Enum.GetNames(userTypeType))
            {
                var memberValue = GetEnumMemberValue(userTypeType.GetMember(item)[0]);
                if (memberValue != null && memberValue.ToLower() == value)
                {
                    return Enum.Parse(userTypeType, item);
                }
            }
        }

        return base.ReadJson(reader, objectType, existingValue, serializer);
    }
}

private static string GetEnumMemberValue(MemberInfo memberInfo)
{
    var attributes = memberInfo.GetCustomAttributes(typeof(EnumMemberAttribute), inherit: false);

    if (attributes.Length == 0) return null;

    return ((EnumMemberAttribute)attributes[0]).Value;
}

在上面的代碼中,我僅檢查EnumMember屬性,因為默認StringEnumConvert已經完成了UserType的成員不區分大小寫的檢查。

請注意,由於檢查,此轉換器僅對您的UserType枚舉有效:

var userTypeType = typeof(UserType);
if (objectType == userTypeType)
{

JsonSerializerSettings初始化替換為:

internal static JsonSerializerSettings JsonSerializerSettings => new JsonSerializerSettings
{
    Converters = new JsonConverter[]
    {
        new UserTypeEnumConverter()
    },
    Formatting = Formatting.Indented
};

我假設Vice-President枚舉數是UserType VicePresident

您可以實現派生自StringEnumConverter的自定義Converter

public class UserTypeEnumConverter : StringEnumConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(UserType);
    }

    public override object ReadJson(JsonReader reader, 
                                    Type objectType, 
                                    object existingValue, 
                                    JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
        {
            var isNullable = (Nullable.GetUnderlyingType(objectType) != null);
            if (!isNullable)
            {
                throw new JsonSerializationException();
            }
            return null;
        }

        var token = JToken.Load(reader);
        var value = token.ToString();
        if (string.Equals(value, "chump", StringComparison.OrdinalIgnoreCase))
        {
            return UserType.Citizen;
        }
        else
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }               
    }
}

轉換器處理基礎類型也可以為空的情況,並且僅在反序列化類上聲明的屬性的類型為UserType時才調用該轉換器。 然后,它檢查所解析的值是否為“不贊成使用的值”,如果不是,則將讀取委托給基本StringEnumConverter

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM