Как сериализовать свойства производных классов с помощью System.Text.JsonHow to serialize properties of derived classes with System.Text.Json
Из этой статьи вы узнаете, как сериализовать свойства производных классов с помощью пространства имен System.Text.Json
.In this article, you will learn how to serialize properties of derived classes with the System.Text.Json
namespace.
Сериализация свойств производных классовSerialize properties of derived classes
Сериализация иерархии полиморфных типов не поддерживается.Serialization of a polymorphic type hierarchy is not supported. Например, если свойство определено как интерфейс или абстрактный класс, сериализуются только свойства, определенные в интерфейсе или абстрактном классе, даже если тип среды выполнения имеет дополнительные свойства.For example, if a property is defined as an interface or an abstract class, only the properties defined on the interface or abstract class are serialized, even if the runtime type has additional properties. В этом разделе описаны исключения из этого поведения.The exceptions to this behavior are explained in this section.
Например, предположим, что у вас есть класс WeatherForecast
и производный класс WeatherForecastDerived
:For example, suppose you have a WeatherForecast
class and a derived class WeatherForecastDerived
:
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
public class WeatherForecastDerived : WeatherForecast
{
public int WindSpeed { get; set; }
}
Предположим также, что аргумент типа метода Serialize
во время компиляции WeatherForecast
:And suppose the type argument of the Serialize
method at compile time is WeatherForecast
:
var options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecast>(weatherForecast, options);
В этом сценарии свойство WindSpeed
не сериализуется, даже если объект weatherForecast
фактически является объектом WeatherForecastDerived
.In this scenario, the WindSpeed
property is not serialized even if the weatherForecast
object is actually a WeatherForecastDerived
object. Сериализуются только свойства базового класса:Only the base class properties are serialized:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Это поведение предназначено для предотвращения случайного доступа к данным в производном типе, созданном во время выполнения.This behavior is intended to help prevent accidental exposure of data in a derived runtime-created type.
Чтобы сериализовать свойства производного типа в предыдущем примере, используйте один из следующих подходов:To serialize the properties of the derived type in the preceding example, use one of the following approaches:
Вызовите перегрузку Serialize, которая позволяет указать тип во время выполнения:Call an overload of Serialize that lets you specify the type at run time:
options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType(), options);
Объявите объект, который должен быть сериализован как
object
.Declare the object to be serialized asobject
.options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize<object>(weatherForecast, options);
В предыдущем примере сценария оба подхода приводят к тому, что WindSpeed
свойство включается в выходные данные JSON:In the preceding example scenario, both approaches cause the WindSpeed
property to be included in the JSON output:
{
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
Важно!
Эти подходы обеспечивают одноэлементную сериализацию только для сериализации корневого объекта, а не для его свойств.These approaches provide polymorphic serialization only for the root object to be serialized, not for properties of that root object.
Вы можете выполнить полиморфную сериализацию для объектов более низкого уровня, если вы определите их как тип object
.You can get polymorphic serialization for lower-level objects if you define them as type object
. Например, предположим, что у класса WeatherForecast
есть свойство PreviousForecast
, которое может быть определено как тип WeatherForecast
или object
:For example, suppose your WeatherForecast
class has a property named PreviousForecast
that can be defined as type WeatherForecast
or object
:
public class WeatherForecastWithPrevious
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
public WeatherForecast PreviousForecast { get; set; }
}
public class WeatherForecastWithPreviousAsObject
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
public object PreviousForecast { get; set; }
}
Если свойство PreviousForecast
содержит экземпляр WeatherForecastDerived
:If the PreviousForecast
property contains an instance of WeatherForecastDerived
:
- Выходные данные JSON из сериализации
WeatherForecastWithPrevious
не содержатWindSpeed
.The JSON output from serializingWeatherForecastWithPrevious
doesn't includeWindSpeed
. - Выходные данные JSON из сериализации
WeatherForecastWithPreviousAsObject
включают в себяWindSpeed
.The JSON output from serializingWeatherForecastWithPreviousAsObject
includesWindSpeed
.
Чтобы сериализовать WeatherForecastWithPreviousAsObject
, не нужно вызывать Serialize<object>
или GetType
, потому что корневой объект не является объектом, который может иметь производный тип.To serialize WeatherForecastWithPreviousAsObject
, it isn't necessary to call Serialize<object>
or GetType
because the root object isn't the one that may be of a derived type. В следующем примере кода не вызывается Serialize<object>
или GetType
:The following code example doesn't call Serialize<object>
or GetType
:
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject, options);
Приведенный выше код правильно сериализует WeatherForecastWithPreviousAsObject
:The preceding code correctly serializes WeatherForecastWithPreviousAsObject
:
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot",
"PreviousForecast": {
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
}
Аналогичный подход к определению свойств object
работает с интерфейсами.The same approach of defining properties as object
works with interfaces. Предположим, что у вас есть следующий интерфейс и реализация и вы хотите сериализовать класс со свойствами, содержащими экземпляры реализации:Suppose you have the following interface and implementation, and you want to serialize a class with properties that contain implementation instances:
using System;
namespace SystemTextJsonSamples
{
public interface IForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
}
public class Forecast : IForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string Summary { get; set; }
public int WindSpeed { get; set; }
}
public class Forecasts
{
public IForecast Monday { get; set; }
public object Tuesday { get; set; }
}
}
Когда вы сериализуете экземпляр Forecasts
, только Tuesday
отображает свойство WindSpeed
, так как Tuesday
определяется как object
:When you serialize an instance of Forecasts
, only Tuesday
shows the WindSpeed
property, because Tuesday
is defined as object
:
var forecasts = new Forecasts
{
Monday = new Forecast
{
Date = DateTime.Parse("2020-01-06"),
TemperatureCelsius = 10,
Summary = "Cool",
WindSpeed = 8
},
Tuesday = new Forecast
{
Date = DateTime.Parse("2020-01-07"),
TemperatureCelsius = 11,
Summary = "Rainy",
WindSpeed = 10
}
};
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(forecasts, options);
В следующем примере показан код JSON, который является результатом предыдущего кода:The following example shows the JSON that results from the preceding code:
{
"Monday": {
"Date": "2020-01-06T00:00:00-08:00",
"TemperatureCelsius": 10,
"Summary": "Cool"
},
"Tuesday": {
"Date": "2020-01-07T00:00:00-08:00",
"TemperatureCelsius": 11,
"Summary": "Rainy",
"WindSpeed": 10
}
}
Дополнительные сведения о полиморфной сериализации и десериализации см. в статье Миграция из Newtonsoft.Json в System.Text.Json.For more information about polymorphic serialization, and for information about deserialization, see How to migrate from Newtonsoft.Json to System.Text.Json.
См. также разделSee also
- Общие сведения о System.Text.JsonSystem.Text.Json overview
- Практическое руководство. Сериализация и десериализация JSONHow to serialize and deserialize JSON
- Создание экземпляров JsonSerializerOptionsInstantiate JsonSerializerOptions instances
- Сопоставление без учета регистраEnable case-insensitive matching
- Настройка имен и значений свойствCustomize property names and values
- Игнорирование свойствIgnore properties
- Применение недействительного кода JSONAllow invalid JSON
- Обработка переполнения JSONHandle overflow JSON
- Сохранение ссылокPreserve references
- Неизменяемые типы и непубличные методы доступаImmutable types and non-public accessors
- Миграция из Newtonsoft.Json в System.Text.JsonMigrate from Newtonsoft.Json to System.Text.Json
- Настройка кодировки символовCustomize character encoding
- Написание пользовательских сериализаторов и десериализаторовWrite custom serializers and deserializers
- Написание пользовательских преобразователей для сериализации JSONWrite custom converters for JSON serialization
- Поддержка DateTime и DateTimeOffsetDateTime and DateTimeOffset support
- Справочник по API System.Text.JsonSystem.Text.Json API reference
- Справочник по API System.Text.Json.SerializationSystem.Text.Json.Serialization API reference