System.Text.Json で派生クラスのプロパティをシリアル化、ファイル保存、読み出し

継承されているクラスのインスタンスをJsonにするためには、属性をつける必要があります
このサンプルでは、実際のコードを示し、各ブロックについて解説をつけています

コード

using System.Text.Encodings.Web;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.Unicode;

WeatherForecastBase weather = new WeatherForecastWithCity
{
    Date = new DateTimeOffset(2025, 9, 26, 0, 0, 0, TimeSpan.FromHours(9)),
    TemperatureCelsius = 30,
    Summary = "涼しい",
    City = "東京",
    Loc = new List<Location> { new Location(1035.6895f, 139.6917f), new Location(100, 100) }
};

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
};

var jsonString = JsonSerializer.Serialize(weather, options);

File.WriteAllText("Weather.json", jsonString);

Console.WriteLine(jsonString);

var weatherLoad = File.ReadAllText("Weather.json");

var json = JsonSerializer.Deserialize<WeatherForecastBase>(weatherLoad);
Console.WriteLine(json);


[JsonDerivedType(typeof(WeatherForecastBase), typeDiscriminator: "base")]
[JsonDerivedType(typeof(WeatherForecastWithCity), typeDiscriminator: "withCity")]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
    public List<Location> Loc { get; set; } = new List<Location>();

    public override string ToString()
    {
        var result = $"Date:{Date}\nTemperatureCelsius:{TemperatureCelsius}\nSummary:{Summary}\nCity:{City}\n";

        result += "Location:\n";

        foreach (var loc in Loc)
        {
            result += $"Latitude:{loc.Latitude} , Longitude{loc.Longitude}\n";
        }

        return result;
    }
}

public class Location
{
    public Location(float latitude, float longitude)
    {
        Latitude = latitude;
        Longitude = longitude;
    }

    public float Latitude { get; set; }
    public float Longitude { get; set; }
}

解説

コード全体

このコードは、C# アプリケーションで天気予報を表示するためのクラスを定義しています。

  1. WeatherForecastBase クラスと WeatherForecastWithCity クラスを定義しています。WeatherForecastWithCity クラスは WeatherForecastBase クラスを継承しています。
  2. WeatherForecastWithCity クラスのインスタンスを作成し、必要なプロパティ(日付、温度、サマリー、都市、緯度経度のリスト)を設定します。
  3. JSON オブジェクトをシリアル化するための JsonSerializerOptions オブジェクトを作成します。
  4. シリアル化された JSON 文字列を作成し、"Weather.json" という名前のファイルに保存します。
  5. “Weather.json" ファイルから JSON 文字列を読み込み、WeatherForecastBase 型にデシリアル化します。

ブロック説明

インスタンス作成

WeatherForecastBase weather = new WeatherForecastWithCity
{
    Date = new DateTimeOffset(2025, 9, 26, 0, 0, 0, TimeSpan.FromHours(9)),
    TemperatureCelsius = 30,
    Summary = "涼しい",
    City = "東京",
    Loc = new List<Location> { new Location(1035.6895f, 139.6917f), new Location(100, 100) }
};

このコードでは、「WeatherForecastWithCity」というクラスのインスタンスを生成しています。このインスタンスは、「Date」、「TemperatureCelsius」、「Summary」、「City」、「Loc」といったプロパティを持ちます。これらのプロパティには、「2025年9月26日」、「30℃」、「涼しい」、「東京」、「位置情報のリスト」などが含まれています。
DateTimeOffset クラスを使って、日本時間を表現するには、TimeSpan.FromHours(9) で UTC から 9 時間引いた時間を設定します。

Jsonシリアライズ(インスタンスを文字列にする)

var options = new JsonSerializerOptions
{
    WriteIndented = true,
    Encoder = JavaScriptEncoder.Create(UnicodeRanges.All),
};

var jsonString = JsonSerializer.Serialize(weather, options);

このコードは、WeatherForecastWithCity クラスのインスタンスを JSON 形式にシリアル化するための処理を行っています。

  1. JsonSerializerOptions オブジェクトを作成します。このオブジェクトはシリアル化の設定を行うために使用されます。ここでは WriteIndented = true に設定しているので、シリアル化された JSON 文字列はインデント付きになります。Encoder プロパティは、シリアル化される文字列のエンコーディングを指定します。ここでは、UnicodeRanges.All によってすべての Unicode 文字を使用できるようになっています。
  2. JsonSerializer.Serialize() メソッドを使用して、WeatherForecastWithCity クラスのインスタンスを JSON 形式にシリアル化します。第1引数にシリアル化するオブジェクト、第2引数に JsonSerializerOptions オブジェクトを渡します。シリアル化された JSON 文字列が返されます。

テキストとしてファイルに書き込み

File.WriteAllText("Weather.json", jsonString);

Console.WriteLine(jsonString);

このコードは、シリアル化された JSON 文字列をファイルに保存し、コンソールに表示する処理を行っています。

  1. File.WriteAllText メソッドを使用して、引数として渡された JSON 文字列を “Weather.json" という名前のファイルに保存します。
  2. Console.WriteLine メソッドを使用して、シリアル化された JSON 文字列をコンソールに出力します。

Jsonフォーマットでテキストファイルから読み取り

var weatherLoad = File.ReadAllText("Weather.json");

var json = JsonSerializer.Deserialize<WeatherForecastBase>(weatherLoad);
Console.WriteLine(json);

このコードは、"Weather.json" ファイルから天気予報データを読み込み、デシリアル化する処理です。

  1. “Weather.json" ファイルから全てのテキストを読み込み、weatherLoad 変数に格納します。
  2. weatherLoad 変数に格納された JSON 文字列を JsonSerializer.Deserialize メソッドに渡し、WeatherForecastBase 型のインスタンスにデシリアル化します。
  3. デシリアル化された天気予報データ(WeatherForecastBase 型のインスタンス)を Console.WriteLine メソッドを使用して表示します。

天気予報情報の基本クラス

[JsonDerivedType(typeof(WeatherForecastBase), typeDiscriminator: "base")]
[JsonDerivedType(typeof(WeatherForecastWithCity), typeDiscriminator: "withCity")]
public class WeatherForecastBase
{
    public DateTimeOffset Date { get; set; }
    public int TemperatureCelsius { get; set; }
    public string? Summary { get; set; }
}

このコードは、気象予報の基本情報を保持するWeatherForecastBaseクラスを定義しています。このクラスは、日付、摂氏温度、およびサマリー情報を含むプロパティを持っています。

また、JsonDerivedType属性を使用して、このクラスを派生クラス(WeatherForecastWithCity)から派生することができるようになっています。この属性は、継承関係を表す際に、JSONシリアル化/デシリアル化処理に役立つ情報を提供するために使用されます。

地域ごとの天気予報のための派生クラス

public class WeatherForecastWithCity : WeatherForecastBase
{
    public string? City { get; set; }
    public List<Location> Loc { get; set; } = new List<Location>();

    public override string ToString()
    {
        var result = $"Date:{Date}\nTemperatureCelsius:{TemperatureCelsius}\nSummary:{Summary}\nCity:{City}\n";

        result += "Location:\n";

        foreach (var loc in Loc)
        {
            result += $"Latitude:{loc.Latitude} , Longitude{loc.Longitude}\n";
        }

        return result;
    }
}

このクラスWeatherForecastWithCityは、基底クラスWeatherForecastBaseを継承しています。このクラスは天気予報情報を表すオブジェクトとして、日付、温度(摂氏)、天気の概要、市名、位置情報を保持します。また、ToString()メソッドがオーバーライドされていますが、このメソッドはオブジェクトを文字列として表示する際の文字列表現を返すものです。

位置情報(Loc)をList型にしているのは、List型メンバーのJson化とファイル保存、読み出しができるかを確認するためです
なので、複数箇所の登録ができるように見えていますが、意味はありません

場所を表すクラス

public class Location
{
    public Location(float latitude, float longitude)
    {
        Latitude = latitude;
        Longitude = longitude;
    }

    public float Latitude { get; set; }
    public float Longitude { get; set; }
}

このコードは、Location クラスを定義しています。

Location クラスは、2つのプロパティ(緯度、経度)を持つクラスです。

Location クラスは、引数付きのコンストラクタを持っていて、緯度と経度を受け取っています。これらのプロパティは、クラスの外部から取得できるようになっています(get アクセサーが定義されています)。

参考

C#,JSON

Posted by hidepon