如何装饰JSON.NET StringEnumConverter

时间:2014-04-07 09:15:43

标签: c# json enums json.net

我正在使用api,它返回这样的字符串值。 some-enum-value

我尝试将这些值放在枚举中,因为默认的StringEnumConverter没有完成这项工作,我试图用一些额外的逻辑来装饰这个转换器。如何确保正确反序列化值?

以下代码是我试图完成这项工作的尝试。但是,由于base.ReadJson无法将字符串识别为JSON,因此行reader = new JsonTextReader(new StringReader(cleaned));打破了整个事情。

有没有更好的方法来实现这一点而无需在StringEnumConverter中实现所有的强制逻辑?如何解决我的方法?

public class BkStringEnumConverter : StringEnumConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.String)
        {
            var enumString = reader.Value.ToString();
            if (enumString.Contains("-"))
            {
                var cleaned = enumString.Split('-').Select(FirstToUpper).Aggregate((a, b) => a + b);
                reader = new JsonTextReader(new StringReader(cleaned));
            }
        }
        return base.ReadJson(reader, objectType, existingValue, serializer);
    }

    private static string FirstToUpper(string input)
    {
        var firstLetter = input.ToCharArray().First().ToString().ToUpper();
        return string.IsNullOrEmpty(input)
            ? input
            : firstLetter + string.Join("", input.ToCharArray().Skip(1));
    }
}

4 个答案:

答案 0 :(得分:56)

我通过在枚举值上添加EnumMember属性解决了这个问题。 Json.NET默认StringEnumConverter完美地处理这些属性。

示例:

public enum MyEnum
{
    [EnumMember("some-enum-value")]
    SomeEnumValue,
    Value,
    [EnumMember("some-other-value")]
    SomeOtherValue
}

请注意,您只需要在破折号或其他特殊字符的情况下指定属性即可在枚举中使用。大写小写由StringEnumConverter处理。因此,如果服务返回类似someenumvalue的值,您应该在枚举Someenumvalue中使用它。如果您更喜欢SomeEnumValue,则应使用EnumMember属性。如果服务像someEnumValue那样返回它,你就可以像SomeEnumValue一样使用它(当你使用CamelCaseText属性时,它可以直接使用)。

您可以在JsonSerializerSettings

中轻松指定转换器和其他设置

以下是我自己使用的设置示例。

new JsonSerializerSettings
{
    ContractResolver = new CamelCasePropertyNamesContractResolver(),
    Converters = new List<JsonConverter> { new StringEnumConverter { CamelCaseText = true } },
    NullValueHandling = NullValueHandling.Ignore
};

答案 1 :(得分:26)

您也可以使用此代码:

[JsonConverter(typeof(StringEnumConverter))]
public enum ResposeStatus
{
    [EnumMember(Value = "success value")]
    Success,
    [EnumMember(Value = "fail value")]
    Fail,
    [EnumMember(Value = "error value")]
    Error
};

序列化JsonConvert.Serialize()时,将使用EnumMember内的文字。

答案 2 :(得分:1)

在Json.NET 12.0.1中,将NamingStrategy添加到StringEnumConverter变得更加容易:

  

新功能-在StringEnumConverter中添加了对NamingStrategy的支持

首先,由于Json.NET没有内置的dash case命名策略,因此可以通过将SnakeCaseNamingStrategy子类化来定义一种命名策略:

public class DashCaseNamingStrategy : SnakeCaseNamingStrategy
{
    protected override string ResolvePropertyName(string name)
    {
        return base.ResolvePropertyName(name).Replace('_', '-');
    }
}

现在,在将转换器构造并添加到constructors时,您可以将其传递给StringEnumConverter的{​​{3}}中的任意一个:

var settings = new JsonSerializerSettings
{
    Converters = { new StringEnumConverter(typeof(DashCaseNamingStrategy)) },
};
var json = JsonConvert.SerializeObject(MyEnum.SomeEnumValue, settings);

Assert.IsTrue(json == "\"some-enum-value\""); // Passes successfully

采用这种方法,MyEnum根本不需要注释。

答案 3 :(得分:0)

你也可以使用这种方法:

public static string GetDescription(this Enum member)
        {
            if (member.GetType().IsEnum == false)
                throw new ArgumentOutOfRangeException(nameof(member), "member is not enum");

            var fieldInfo = member.GetType().GetField(member.ToString());

            if (fieldInfo == null)
                return null;

            var attributes = fieldInfo.GetCustomAttributes<DescriptionAttribute>(false).ToList();

            return attributes.Any() ? attributes.FirstOrDefault()?.Description : member.ToString();
        }

public static string GetDescription(this object member)
        {
            var type = member.GetType();

            var attributes = type.GetCustomAttributes<DescriptionAttribute>(false).ToList();

            return attributes.Any() ? attributes.FirstOrDefault()?.Description : member.GetType().Name;
        }

和枚举应具有 desctription 属性。像这样:

public enum MyEnum
    {
        [Description("some-enum-value")]
        And,
        [Description("some-enum-value")]
        Or

    }

而且你可以像这样使用你的enum

MyEnum.GetDescription(); //return "some-enum-value"