如何装饰JSON.NET StringEnumConverter

Mar*_*rco 37 c# enums json json.net

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

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

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

有没有更好的方法来实现这一点,而无需在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));
    }
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*rco 65

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

例:

public enum MyEnum
{
    [EnumMember(Value = "some-enum-value")]
    SomeEnumValue,
    Value,
    [EnumMember(Value = "some-other-value")]
    SomeOtherValue
}
Run Code Online (Sandbox Code Playgroud)

请注意,您只需要在破折号或其他特殊字符的情况下指定属性,您不能在枚举中使用.大写的小写由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
};
Run Code Online (Sandbox Code Playgroud)

  • 小评论。如果您不使用 StringEnumConverter,而是使用 json.net 的默认值,则 enumMember 将不起作用。 (2认同)
  • 您是否需要在 `enum` 定义上方添加 `[JsonConverter(typeof(StringEnumConverter))]`? (2认同)

A-S*_*ani 30

您也可以使用此代码:

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

序列化时JsonConvert.Serialize(),会使用里面的文字EnumMember.


dbc*_*dbc 10

在 Json.NET 12.0.1 中,通过添加NamingStrategyto使这变得更容易StringEnumConverter

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

并且 Json.NET 12.0.3添加了KebabCaseNamingStrategy连字符分隔的烤肉串外壳,例如some-enum-value

新功能 - 添加了 KebabCaseNamingStrategy

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

具体而言,在12.0.3及更高版本,你可以通过KebabCaseNamingStrategy到任何的几个的构造函数StringEnumConverter构造和添加转换器时JsonSerializerSettings.Converters

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

Assert.IsTrue(json == "\"some-enum-value\""); // Passes successfully
Run Code Online (Sandbox Code Playgroud)

这样做后,您的序列化枚举值现在将是 kebab-cased。演示小提琴 #1在这里

在 Json.NET 12.0.1 和 12.0.2 中,您可以通过子类化来定义自己的烤肉串命名策略SnakeCaseNamingStrategy

public class KebabCaseNamingStrategy : SnakeCaseNamingStrategy
{
    protected override string ResolvePropertyName(string name)
    {
        return base.ResolvePropertyName(name).Replace('_', '-');
    }
}
Run Code Online (Sandbox Code Playgroud)

演示小提琴 #2在这里