System.Text.Json で派生クラスのプロパティをシリアル化する方法
この記事では、System.Text.Json
名前空間を使用して派生クラスのプロパティをシリアル化する方法について説明します。
派生クラスのプロパティのシリアル化
ポリモーフィック型の階層のシリアル化はサポートされて "いません"。 たとえば、プロパティがインターフェイスまたは抽象クラスとして定義されている場合は、ランタイム型に追加のプロパティがある場合でも、インターフェイスまたは抽象クラスに定義されたプロパティのみがシリアル化されます。 この動作の例外については、このセクションで説明します。
たとえば、WeatherForecast
クラスと派生クラス WeatherForecastDerived
があるとします。
public class WeatherForecast
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
}
Public Class WeatherForecast
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
End Class
public class WeatherForecastDerived : WeatherForecast
{
public int WindSpeed { get; set; }
}
Public Class WeatherForecastDerived
Inherits WeatherForecast
Public Property WindSpeed As Integer
End Class
また、コンパイル時の Serialize
メソッドの型引数が WeatherForecast
であるとします。
var options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize<WeatherForecast>(weatherForecast, options);
Dim options As JsonSerializerOptions = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecast1, options)
このシナリオでは、weatherForecast
オブジェクトが実際には WeatherForecastDerived
オブジェクトであっても、WindSpeed
プロパティはシリアル化されません。 基本クラスのプロパティのみがシリアル化されます。
{
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
この動作は、ランタイムによって作成される派生型内でデータが誤って公開されるのを防ぐためのものです。
前の例で派生型のプロパティをシリアル化するには、次のいずれかのアプローチを使用します。
実行時に型を指定できるようにする Serialize のオーバーロードを呼び出します。
options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize(weatherForecast, weatherForecast.GetType(), options);
options = New JsonSerializerOptions With { .WriteIndented = True } jsonString = JsonSerializer.Serialize(weatherForecast1, weatherForecast1.[GetType](), options)
オブジェクトを
object
としてシリアル化するように宣言します。options = new JsonSerializerOptions { WriteIndented = true }; jsonString = JsonSerializer.Serialize<object>(weatherForecast, options);
options = New JsonSerializerOptions With { .WriteIndented = True } jsonString = JsonSerializer.Serialize(Of Object)(weatherForecast1, options)
前の例のシナリオでは、どちらのアプローチでも、WindSpeed
プロパティが JSON 出力に含まれるようになります。
{
"WindSpeed": 35,
"Date": "2019-08-01T00:00:00-07:00",
"TemperatureCelsius": 25,
"Summary": "Hot"
}
重要
これらのアプローチでは、シリアル化するルート オブジェクトに対してのみポリモーフィックなシリアル化が提供され、そのルート オブジェクトのプロパティに対しては提供されません。
object
型として定義すると、下位レベルのオブジェクトのポリモーフィックなシリアル化を取得できます。 たとえば、WeatherForecast
クラスに、WeatherForecast
または object
型として定義できる PreviousForecast
という名前のプロパティがあるとします。
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 WeatherForecastWithPrevious
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
Public Property PreviousForecast As WeatherForecast
End Class
public class WeatherForecastWithPreviousAsObject
{
public DateTimeOffset Date { get; set; }
public int TemperatureCelsius { get; set; }
public string? Summary { get; set; }
public object? PreviousForecast { get; set; }
}
Public Class WeatherForecastWithPreviousAsObject
Public Property [Date] As DateTimeOffset
Public Property TemperatureCelsius As Integer
Public Property Summary As String
Public Property PreviousForecast As Object
End Class
PreviousForecast
プロパティに WeatherForecastDerived
のインスタンスが含まれる場合:
WeatherForecastWithPrevious
のシリアル化からの JSON 出力には、WindSpeed
がWeatherForecastWithPrevious
。WeatherForecastWithPreviousAsObject
のシリアル化からの JSON 出力には、WindSpeed
がWeatherForecastWithPreviousAsObject
。
ルート オブジェクトは派生型である可能性があるものではないため、WeatherForecastWithPreviousAsObject
をシリアル化するために Serialize<object>
または GetType
を呼び出す必要はありません。 次のコード例では Serialize<object>
または GetType
は呼び出されません。
options = new JsonSerializerOptions
{
WriteIndented = true
};
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject, options);
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(weatherForecastWithPreviousAsObject1, options)
上記のコードでは、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
と同じプロパティ定義のアプローチがインターフェイスで機能します。 次のインターフェイスと実装があり、実装インスタンスを含むプロパティを使用してクラスをシリアル化するとします。
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; }
}
}
Namespace SystemTextJsonSamples
Public Interface IForecast
Property [Date] As DateTimeOffset
Property TemperatureCelsius As Integer
Property Summary As String
End Interface
Public Class Forecast
Implements IForecast
Public Property [Date] As DateTimeOffset Implements IForecast.[Date]
Public Property TemperatureCelsius As Integer Implements IForecast.TemperatureCelsius
Public Property Summary As String Implements IForecast.Summary
Public Property WindSpeed As Integer
End Class
Public Class Forecasts
Public Property Monday As IForecast
Public Property Tuesday As Object
End Class
End Namespace
Forecasts
のインスタンスをシリアル化する場合、Tuesday
は object
として定義されているので、Tuesday
にのみ WindSpeed
プロパティが表示されます。
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);
Dim forecasts1 As New Forecasts With {
.Monday = New Forecast With {
.[Date] = Date.Parse("2020-01-06"),
.TemperatureCelsius = 10,
.Summary = "Cool",
.WindSpeed = 8
},
.Tuesday = New Forecast With {
.[Date] = Date.Parse("2020-01-07"),
.TemperatureCelsius = 11,
.Summary = "Rainy",
.WindSpeed = 10
}
}
options = New JsonSerializerOptions With {
.WriteIndented = True
}
jsonString = JsonSerializer.Serialize(forecasts1, options)
次の例は、前のコードから生成された JSON を示しています。
{
"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
}
}
Note
この記事では、逆シリアル化ではなくシリアル化について説明します。 ポリモーフィックな逆シリアル化はサポートされていませんが、回避策として、「ポリモーフィックな逆シリアル化のサポート」の例に示すようなカスタム コンバーターを記述できます。
関連項目
- の概要
- JSON をシリアル化および逆シリアル化する方法
- JsonSerializerOptions インスタンスのインスタンスを作成する
- 大文字と小文字を区別しない一致を有効にする
- プロパティの名前と値をカスタマイズする
- プロパティを無視する
- 無効な JSON を許可する
- オーバーフロー JSON を処理するか、JsonElement または JsonNode を使用する
- 参照を保持し、循環参照を処理する
- 変更できない型と非パブリック アクセサーに逆シリアル化する
- から System.Text.Json に移行する
- 文字エンコードをカスタマイズする
- DOM、Utf8JsonReader、Utf8JsonWriter を使用する
- JSON シリアル化のためのカスタム コンバーターの作成
- DateTime および DateTimeOffset のサポート
- ソース生成を使用する方法
- サポートされているコレクション型
- API リファレンス
- .Serialization API リファレンス