このドキュメントの内容
System.Text.Json.JsonSerializer クラスでの派生クラスのシリアライズについて簡単に説明します。
詳しくは、マイクロソフトの .NET ガイドの派生クラスのプロパティのシリアル化の項で説明されています。
サンプルクラス
ローカルファイルまたはデータベースをデータソースとするアプリケーションの動作設定を、次のようなコンフィグクラスで表したとします。FileConfig クラスと DatabaseConfig クラスは DataSourceConfig クラスから派生しています。
publicclassApplicationConfig{publicDataSourceConfigDataSource{get;set;}}publicclassDataSourceConfig{publicstringName{get;set;}}publicclassFileConfig:DataSourceConfig{publicstringFilePath{get;set;}}publicclassDatabaseConfig:DataSourceConfig{publicstringConnectionString{get;set;}}シリアライズ対象のインスタンス自身が派生型である場合
単純にシリアライズしたときの結果
privatestringSerializeDataSourceConfig(){// 基底型で宣言DataSourceConfigconfig=newFileConfig(){Name="file1",FilePath=@"d:\test.csv"};returnJsonSerializer.Serialize(config,GetOptions());}privatestringSerializeFileConfig(){// 派生型で宣言FileConfigconfig=newFileConfig(){Name="file1",FilePath=@"d:\test.csv"};returnJsonSerializer.Serialize(config,GetOptions());}privateJsonSerializerOptionsGetOptions(){returnnewJsonSerializerOptions(){WriteIndented=true};}シリアライザに渡された型の型情報から出力対象のプロパティが決定されます。基底型である DataSourceConfig クラスが渡された場合、派生型で定義されているプロパティは出力対象になりません。
{
"Name": "file1"
}
{
"FilePath": "d:\\test.csv",
"Name": "file1"
}
派生型で定義されているプロパティを出力対象にするには
Serialize メソッドの引数にシリアライズ対象インスタンスの型を渡すか、Serialize メソッドの型情報に object を指定します。
privatestringSerializeDataSourceInheritConfig1(){// 基底型で宣言DataSourceConfigconfig=newFileConfig(){Name="file1",FilePath=@"d:\test.csv"};// 引数でインスタンスの型を渡すreturnJsonSerializer.Serialize(config,config.GetType(),GetOptions());}privatestringSerializeDataSourceInheritConfig2(){// 基底型で宣言DataSourceConfigconfig=newFileConfig(){Name="file1",FilePath=@"d:\test.csv"};// ジェネリックパラメーターで object を指定するreturnJsonSerializer.Serialize<object>(config,GetOptions());}どちらも出力結果は同じです。FileCondig クラスで定義されているプロパティの値も出力されます。
{
"FilePath": "d:\\test.csv",
"Name": "file1"
}
{
"FilePath": "d:\\test.csv",
"Name": "file1"
}
シリアライズ対象インスタンスのプロパティに、その派生型のインスタンスが格納されている場合
単純にシリアライズしたときの結果
privatestringSerializeApplicationConfig(){ApplicationConfigconfig=newApplicationConfig(){DataSource=newFileConfig(){Name="file1",FilePath=@"d:\test.csv"}};returnJsonSerializer.Serialize(config,GetOptions());}ApplicationConfig.DataSource の型は DataSourceConfig クラスであるため、FileConfig で定義されているプロパティは出力対象になりません。
{
"DataSource": {
"Name": "file1"
}
}
派生型で定義されているプロパティを出力対象にするには
古典的な方法ですが、シリアライズ目的の object 型プロパティを定義します。本来のプロパティはシリアライズ対象外になるように属性でマークします。
前述の ApplicationConfig クラスを次のように変更します。
- DataSource プロパティに JsonIgnore 属性を付与します。
- DataSource プロパティの値も読み書きを行う object 型の DataSourceObject プロパティを定義します。
- JsonPropertyName 属性を付与し、"DataSource" という名前でシリアライズされるようにしています。
- Browsable 属性と EditorBrowsable 属性を付与し、表に現れにくくしています。
// using System.ComponentModel;// using System.Text.Json.Serialization;publicclassApplicationConfig{[JsonIgnore]publicDataSourceConfigDataSource{get;set;}[JsonPropertyName("DataSource")][Browsable(false)][EditorBrowsable(EditorBrowsableState.Never)]publicobjectDataSourceObject{get{returnDataSource;}set{DataSource=(DataSourceConfig)value;}}}FileConfig クラスで定義されているプロパティもシリアライズ対象になります。DataSourceObject プロパティの値がシリアライズされる際、JsonSerializer.Serialize メソッドに object 型が渡され、プロパティの型ではなくインスタンスの型が使用されるようになるためです。
{
"DataSource": {
"FilePath": "d:\\test.csv",
"Name": "file1"
}
}
まとめ
アプリケーションの動作設定をファイルから読み込むような目的であれば、この方法で問題はなさそうです。