Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Начиная с .NET 11, JsonSerializer поддерживает типы объединения C# 15. Объединение содержит один из типов случаев в своем объявлении.
JsonSerializer записывает значение активного варианта и может считать его обратно.
Сериализация и десериализация значений объединения
Объявите объединение, варианты которого имеют различные типы токенов JSON:
public union Payload(int, string, Message);
public sealed record Message(string Text);
Используйте JsonSerializer для сериализации и десериализации объединения:
Payload payload = new Message("Ready");
string json = JsonSerializer.Serialize(payload);
Payload copy = JsonSerializer.Deserialize<Payload>(json);
Сериализованный JSON содержит значение активного варианта, а не объект-обёртку или дискриминатор:
{"Text":"Ready"}
По умолчанию сериализатор классифицирует входящие JSON по типу токена. В предыдущем объединении число JSON выбирает int, строка JSON выбирает string, а объект JSON выбирает Message.
С помощью int объект JsonSerializerOptions.Web также можно считывать из строки JSON. И int, и string случаи Payload затем сопоставляются с типом строкового токена. Даже "25%" выдаёт JsonException из-за неоднозначности, прежде чем сериализатор обработает любой из вариантов. Чтобы считывать строки с веб-значениями по умолчанию, укажите пользовательский классификатор , который выбирает вариант.
Различает случаи с одинаковым типом токена JSON
Классификация токенов не может различать два случая, которые сериализуются как объекты JSON. Примените JsonUnionAttribute и выберите JsonUnionTypeStructuralClassifier для классификации вариантов объектов по именам свойств:
[JsonUnion(TypeClassifier = typeof(JsonUnionTypeStructuralClassifier))]
public union Pet(Dog, Cat);
public sealed record Dog(string Name, string Breed);
public sealed record Cat(string Name, int Lives);
JsonUnionAttribute Здесь выбирает классификатор для существующего Pet объединения. Применение его к обычному типу не превращает этот тип в объединение.
Классификатор выбирает Dog, когда полезная нагрузка содержит Breed, и выбирает Cat, когда она содержит Lives:
Pet pet = JsonSerializer.Deserialize<Pet>(
"""{"Name":"Rex","Breed":"Husky"}""");
Для объектов JSON структурный классификатор сначала рассматривает набор совместимых вариантов объектов и сужает этот набор по мере считывания распознанных имён свойств верхнего уровня. Обязательные свойства исключают случаи, в которых они отсутствуют. JsonUnmappedMemberHandling.Disallow Удаляет сценарий, когда передаваемые данные содержат свойство, которое в нём не объявлено. Классификация выполняется только в том случае, если остается один случай.
Структурный классификатор не проверяет значения свойств, вложенные объекты, содержимое строки или элементы массива. Имейте в виду следующие последствия:
- Полезная нагрузка, которая не оставляет ни одного кандидата или оставляет несколько кандидатов, вызывает исключение JsonException.
- При создании классификатора перекрывающиеся или затенённые контракты объектов могут быть отклонены.
- Несколько случаев, не связанных с объектами и использующих один и тот же тип токена JSON, не поддерживаются. Например,
Guidиstringоба используют строки JSON. - Вариант с обычным объектом нельзя смешивать со словарём,
JsonObject, или другим вариантом в форме объекта, не относящимся к POCO. - Вложенные варианты объединения и полиморфные варианты не поддерживаются.
- ReferenceHandler.Preserve не поддерживается.
- Конфигурация, которая не может различать свои варианты, вызывает исключение NotSupportedException, когда сериализатор строит классификатор.
Выбор профсоюзов или закрытых иерархий
Используйте объединение, если необходимо сохранить формат JSON без дискриминации, который вы не контролируете, или если в случаях имеются отдельные фигуры JSON. Например, случаи int и string для Payload различаются по типу токена JSON. Однако в таких случаях, как Pet(Dog, Cat)изменения имен свойств, могут повлиять на то, какой случай выбирает структурный классификатор.
Если вы контролируете типы и JSON-контракт, закрытая иерархия с выводимым полиморфизмом может вместо этого различать типы объектов с помощью дискриминатора:
[JsonPolymorphic(InferClosedTypePolymorphism = true)]
public closed record Event;
public sealed record Created(int Id) : Event;
public sealed record Deleted(int Id) : Event;
JsonSerializer.Serialize<Event>(new Created(42)) записывает {"$type":"Created","Id":42}. Оба производных типа объявляют Id, но дискриминатор определяет вариант независимо от его свойств. Это делает выбор вариантов более стабильным по мере развития свойств. В отличие от случаев объединения производные типы должны иметь общий базовый класс, и вы должны явно включить выводимый полиморфизм; сам по себе модификатор closed не добавляет дискриминатор.
Предоставление пользовательского классификатора
Производный от того JsonTypeClassifierFactory , когда классификация маркеров по умолчанию или встроенная JsonUnionTypeStructuralClassifier не соответствует вашим требованиям. Настраиваемый классификатор может использовать другие структурные правила для выбора варианта объединения. Зарегистрируйте фабрику в одном из следующих расположений:
- Назначьте делегат для JsonTypeInfo.TypeClassifier при настройке контракта.
- Задайте JsonUnionAttribute.TypeClassifier для одного объединения.
- Добавьте фабрику в JsonSerializerOptions.TypeClassifiers для сериализации с использованием рефлексии.
- Задайте JsonSourceGenerationOptionsAttribute.TypeClassifiers для контекста генерации исходного кода.
Классификатор читает текущее значение JSON и возвращает один из типов случаев из JsonTypeClassifierContext.UnionCases. Сериализатор сначала проверяет делегат контракта, за которым следует фабрика по каждому союзу, фабрики на уровне параметров и встроенная классификация маркеров.
Для неоднозначных объединений генератор исходного кода выдаёт диагностическое сообщение, если во время генерации не настроен классификатор.
Обработка значений null и значений объединения по умолчанию
Объединение может объявлять типы вариантов, допускающие значение null. JSON null выбирает первый вариант, допускающий значение NULL. Если в объединении нет варианта, допускающего значение null, JSON null возвращает значение по умолчанию для объединения. Для объединения структурного типа, созданного компилятором, значение по умолчанию не имеет активного варианта и сериализуется в JSON как null.
Настройка контракта профсоюза
Для расширенных сценариев настройте метаданные объединения с помощью JsonTypeInfo. Значение объединения JsonTypeInfo.Kind равно JsonTypeInfoKind.Union. Контракт включает:
- JsonTypeInfo.UnionCases, содержащий JsonUnionCaseInfo записи.
- JsonTypeInfo.UnionConstructor, который формирует объединение из типа варианта и значения.
- JsonTypeInfo.UnionDeconstructor, возвращает активный тип падежа и значение.
- JsonTypeInfo.TypeClassifier, который выбирает вариант при десериализации.
Дополнительные сведения об изменении JsonTypeInfoсм. в разделе "Настройка контракта JSON".