皆さんこんにちは、沙漠の果ての狼です。
一. 問題の説明
下図のように、Student と Employ という2つのサブクラスを定義し、両方とも抽象クラス PersonBase を継承します:
public abstract class PersonBase
{
public string Name { get; set; }
protected PersonBase(string name)
{
Name = name;
}
}
public class Student : PersonBase
{
public string Number { get; set; }
public Student(string name, string number) : base(name)
{
Number = number;
}
}
public class Employ : PersonBase
{
public string CompanyName { get; set; }
public Employ(string name, string companyName) : base(name)
{
CompanyName = companyName;
}
}
Web API インターフェースを追加し、基底クラスのコレクションを返します:
[ApiController]
[Route("[controller]")]
public class TestController : ControllerBase
{
[HttpGet(Name = "GetDetails")]
public IEnumerable<PersonBase> Get()
{
return new List<PersonBase>()
{
new Student("学生A", "学生号01"),
new Employ("职员01", "百度")
};
}
}
インターフェースの戻り値:
[
{
"name": "学生A"
},
{
"name": "职员01"
}
]
問題に気づきましたか?Student クラスと Employ クラスのインスタンスの拡張プロパティ(Student の Number プロパティ、Employ の CompanyName プロパティ)がシリアライズされて表示されていません。では、どうすればサブクラスのすべてのプロパティをシリアライズできるのでしょうか?
二、クラスの全プロパティをシリアライズする方法
Microsoft のドキュメント「System.Text.Json を使用して派生クラスのプロパティをシリアライズする方法」を参考に、管理者が比較的簡単だと考える2つの実装方法を紹介します。
2.1、.NET 7 より前の実装方法
.NET 7 より前のバージョンでは、System.Text.Json はポリモーフィックな型階層のシリアライズをサポートしていません。例えば、インターフェースの戻り値の型がインターフェースや抽象クラスのコレクションである場合、実行時の型が他のプロパティを持っていても、インターフェースや抽象クラスで定義されたプロパティのみがシリアライズされます。
解決策: インターフェースの戻り値を IEnumerable<PersonBase> から object に変更し、インターフェース実装内の List<PersonBase> を List<object> に変更します:
[HttpGet(Name = "GetDetails")]
public object Get()
{
return new List<object>()
{
new Student("学生A", "学生号01"),
new Employ("职员01", "百度")
};
}
変更後、インターフェースは詳細な JSON 情報を正常に返します:
[
{
"number": "学生号01",
"name": "学生A"
},
{
"companyName": "百度",
"name": "职员01"
}
]
原理: object に変更すると、デフォルトで実装クラスがシリアライズされるようになります。変更前は System.Text.Json が実装クラスの親クラスしか認識していませんでした。
2.2、.NET 7 以降の実装方法
.NET 7 以降、System.Text.Json は属性を使用したポリモーフィックな型階層のシリアライズとデシリアライズをサポートしています。
インターフェースを元に戻し、抽象クラスに属性を追加して、基底クラスをシリアライズする際にマッピングするサブクラスの型を指定します:
[JsonDerivedType(typeof(Student))]
[JsonDerivedType(typeof(Employ))]
public abstract class PersonBase
問題は解決され、インターフェースの戻り値は上記と同じになります。
ドキュメントでは JsonDerivedTypeAttribute について次のように説明されています:型宣言に配置すると、ポリモーフィックシリアライゼーションのために指定されたサブタイプを選択する必要があることを示します。また、型識別子を指定する機能も公開します。
三、まとめ
上記2つの方法は、.NET のバージョンに応じて選択します。2つ目の方法では、サブクラスの型を明確に把握している必要があります。詳細な使用方法は Microsoft のドキュメント「System.Text.Json を使用して派生クラスのプロパティをシリアライズする方法」をご覧ください。
より良い方法があれば、ぜひコメントでご共有ください。
- WeChat 技術交流グループ:WeChat(codewf)を追加し、「入群」とコメント
- QQ 技術交流グループ:771992300
- 画像リンクはそのまま掲載
