#c# #json
#c# #json
Вопрос:
Мне нужно настроить способ Newtonsoft.Json сериализует объект, в частности, о типах перечислений. Учитывая пример класса, подобного этому:
public class TestEnumClass
{
public Enum ReferencedEnum { get; set; }
public string OtherProperty { get; set; }
public StringSplitOptions OtherEnum { get; set; }
}
Сериализация по умолчанию будет происходить таким образом:
var testEnumClass = new TestEnumClass
{
ReferencedEnum = StringComparison.OrdinalIgnoreCase,
OtherProperty = "Something",
OtherEnum = StringSplitOptions.None
};
var serialized = JsonConvert.SerializeObject(testEnumClass, Formatting.Indented);
И сериализованная строка будет:
{
"ReferencedEnum": 5,
"OtherProperty": "Something",
"OtherEnum": 0
}
Здесь у меня 2 проблемы:
- Я не могу гарантировать, что порядок перечислений останется прежним (здесь я использую перечисления, включенные в фреймворк, но в моем проекте есть другие перечисления, производные от «: Enum»), поэтому я не могу сохранить число в качестве сериализованного значения перечисления.
- Во-вторых, и это более важно, это тот факт, что поле «ReferencedEnum» объявлено как «Enum», и в это поле может быть записано любое перечисление (ReferencedEnum = AnyEnum.AnyEnumValue). Это приводит к тому, что при десериализации значения мне нужно знать исходный тип перечисления (в примере это сравнение строк).
Я думал об использовании конвертера (производного от «: JsonConverter») и манипулировании тем, что записывается и читается. Результат, о котором я думал, был примерно таким:
{
"ReferencedEnum": {
"EnumType": "StringComparison",
"EnumValue": "OrdinalIgnoreCase"
},
"OtherProperty": "Something",
"OtherEnum": "StringSplitOptions.None"
}
Таким образом, десериализатор будет знать:
- для свойств «Enum» укажите исходный тип и строковое значение.
- для свойств «типизированного перечисления» (specific enum) — полный тип и значение.
Что я не могу абсолютно добавить, так это ссылку на конвертер в классе модели, подобную этой:
[JsonConverter(typeof(EnumConverter))]
public Enum ReferencedEnum { get; set; }
И я бы также избегал наличия поля «$ type» в сериализованной строке (за исключением случаев, когда это единственное решение).
Кстати, я могу добавить общий атрибут, подобный этому:
[IsEnum]
public Enum ReferencedEnum { get; set; }
Есть ли у кого-нибудь идеи о том, как я могу получить необходимый результат?
Спасибо!
Ответ №1:
Я столкнулся с той же проблемой и разработал пакет nuget с именем StringTypeEnumConverter, который решает ее. Вы можете проверить проект здесь. Использование будет таким же простым, как и любой другой конвертер.
Этот конвертер является производным от уже существующего «StringEnumConverter», который записывает строковое значение перечисления вместо его числового аналога. Я также добавил поддержку написания имени типа.
Результат будет выглядеть следующим образом: "StringSplitOptions.None"
(это строковое значение, а не объект).
Обратите внимание, что этот конвертер следует применять как для записи, так и для чтения, поскольку результирующий json не будет совместим с другими программами чтения, не включающими этот конвертер.
Вам следует рассмотреть возможность использования этого пакета, только если вы не можете избежать использования перечислений в вашей модели. Я бы также посоветовал вам потратить время, чтобы проверить, могут ли (пользовательские) перечисления быть преобразованы в классы.
J.
Комментарии:
1. Спасибо, похоже, это решает мою проблему. Я согласен с вами, что лучше избегать использования перечислений при сериализации, но в моем случае я застрял с данной моделью.