Вопрос:

Как украсить JSON.NET StringEnumConverter

c# json enums json.net

25099 просмотра

4 ответа

2274 Репутация автора

Я использую 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));
    }
}
Автор: Marco Franssen Источник Размещён: 07.04.2014 09:15

Ответы (4)


57 плюса

2274 Репутация автора

Решение

Я решил проблему, добавив атрибуты EnumMember в мои значения enum. По умолчанию Json.NET StringEnumConverterпрекрасно справляется с этими атрибутами.

Пример:

public enum MyEnum
{
    [EnumMember(Value = "some-enum-value")]
    SomeEnumValue,
    Value,
    [EnumMember(Value = "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
};
Автор: Marco Franssen Размещён: 08.04.2014 01:43

28 плюса

6771 Репутация автора

Вы также можете использовать этот код:

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

При сериализации JsonConvert.Serialize(), будет использовать текст внутри EnumMember.

Автор: A-Sharabiani Размещён: 23.06.2016 08:28

0 плюса

405 Репутация автора

Также вы можете использовать эти методы:

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

и enum должен иметь атрибут desctription . Как это:

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

    }

И чем вы можете использовать свой enumвот так:

MyEnum.GetDescription(); //return "some-enum-value"
Автор: Maksym Labutin Размещён: 02.02.2018 08:40

1 плюс

57770 Репутация автора

Это было легче в Json.NET 12.0.1 с добавлением NamingStrategyк StringEnumConverter:

Новая функция - добавлена ​​поддержка NamingStrategy в StringEnumConverter

Во-первых, поскольку в Json.NET нет стратегии присвоения имен тире , встроенной в подклассы SnakeCaseNamingStrategy:

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

Теперь вы можете передать его в любой из нескольких конструкторов для StringEnumConverterпри создании и добавления конверторов JsonSerializerSettings.Converters:

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таком подходе аннотации вообще не требуются .

Автор: dbc Размещён: 17.12.2018 06:36
Вопросы из категории :
32x32