[C#] ジェネリクスでいろいろなjsonファイルの読み書きできるようにする

# もくじ

https://tera1707.com/entry/2022/02/06/144447

# json関連記事
https://tera1707.com/entry/2022/02/06/144447#json

# やりたいこと

[以前勉強したjsonファイルの読み書きのやり方](https://qiita.com/tera1707/items/2a774f4a76c48fc849fa)で、jsonを扱えるようになったが、シリアライズ、デシリアライズするときに毎回そのときに使う型を指定していたので、jsonファイルが増えるたびに同じようなシリアライズ、デシリアライズのメソッドを作らないといけなかった。

さすがにこれではほぼ同じ内容の、型だけ違ったコードが乱立していけてないので、共通のコードでなんとかできるようにしたい。

# 前提

`.NET6 / C#10` を使用。

# やり方

ジェネリクスで、使うjsonデータのクラスの型を指定して、シリアライズ、デシリアライズできるようにした。

2つの実験用jsonファイルをまず手で作成し、

- jsonを読み込んでデシリアライズしjsonObjectを作成する
- そのjsonObjectをシリアライズし、ファイルに保存する

ということをした。

# 実験用jsonファイル

作った実験用jsonファイルは下記。

```json1.json
{
"data1":1,
"data2":"aiueo",
"data3":true,
"arraydata":
[
    {
        "data11":1,
        "small": [
            123.456,
            789.012
        ],
        "large": [
            987.654,
            654.321
        ]
    },
    {
        "data11":2,
        "small": [
            111.456,
            222.012
        ],
        "large": [
            333.654,
            444.321
        ]
    }
]
}
```

```json2.json
{
	"Value1":10,
	"Flag1":true,
}
```

# ファイル読み書き ＆ シリアライズ/デシリアライズ用クラス

上のjsonファイルに対して、

- ファイルを読み込んでデシリアライズ(json文字列→jsonオブジェクト化)
- シリアライズ(jsonオブジェクト→json文字列化)してファイルに書き込み

を、下のクラスを使って行う。
(拡張メソッド)

```cs
public static class Json
{
    // jsonオブジェクトをシリアライズしてファイルに書き込む
    public static void ToJsonFile<T>(this T jsonObj, string path)
    {
        try
        {
            var str = jsonObj.ToStringFromJsonObject<T>();

            using (var fs = new FileStream(path, FileMode.Create))
            using (var sw = new StreamWriter(fs))
            {
                sw.Write(str);
            }
        }
        catch (Exception ex)
        {
            throw;
        }
    }

    // jsonオブジェクトを文字列に変換する
    public static string ToStringFromJsonObject<T>(this T jsonObj)
    {
        string json = string.Empty;
        var stream = new MemoryStream();
        try
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            serializer.WriteObject(stream, jsonObj);
            json = Encoding.UTF8.GetString(stream.ToArray());
        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            stream.Dispose();
        }
        return json;
    }

    // jsonファイルの中身を読みだしてjsonオブジェクトに変換する
    public static T? ToJsonObjectFromJsonFile<T>(this string path)
    {
        string data = string.Empty;

        using (var fs = new FileStream(path, FileMode.Open))
        using (var sr = new StreamReader(fs))
        {
            data = sr.ReadToEnd();
        }

        var jsonObj = data.ToJsonObject<T>();

        return jsonObj;
    }

    // jsonの文字列をjsonオブジェクトに変換する
    public static T? ToJsonObject<T>(this string json)
    {
        var stream = new MemoryStream(Encoding.UTF8.GetBytes(json));
        var data = default(T);

        try
        {
            var serializer = new DataContractJsonSerializer(typeof(T));
            data = (T?)serializer.ReadObject(stream);
        }
        catch (Exception ex)
        {
            throw;
        }
        finally
        {
            stream.Dispose();
        }
        return data;
    }
}
```

# 作ったクラスを使う

上のクラスを使って、jsonファイルにシリアライズ/デシリアライズする

``` Program.cs
using System.Runtime.Serialization.Json;
using System.Text;

var jsonPath1 = @"C:\Users\user1\Desktop\json1.json";
var jsonPath2 = @"C:\Users\user1\Desktop\json2.json";

var j1 = jsonPath1.ToJsonObjectFromJsonFile<Rootobject1>();
j1.ToJsonFile(@"C:\Users\masa\Desktop\json1_copy.json");

var j2 = jsonPath2.ToJsonObjectFromJsonFile<Rootobject2>();
j2.ToJsonFile(@"C:\Users\masa\Desktop\json2_copy.json");
```

これをすると、いったんデシリアライズして作成したjsonオブジェクトを、再度シリアライズして文字列に直し、ファイル出力する。

内容を見ると(改行等がされてはいないものの)、同じデータが記録されているので、正しく変換できていることが確認できる。

# 参考

元になるシリアライズ、デシリアライズのメソッドはこちらを参考に作成させていただいた。ありがとうございます。

https://mokake.hatenablog.com/entry/2017/09/12/195656

シリアライズしたjsonのファイルの見た目をよくしたい(改行などしたい)と思ったらこちら

https://mokake.hatenablog.com/entry/2017/09/28/234433

ファイルの読み書き

https://qiita.com/tera1707/items/65025aca202ef0535fa5