【C#】JSONデータをデシリアライズする際のデータクラスや属性の定義方法

# 概要
C#でJSONデータをデシリアライズする際の、データクラスの構成や属性定義についてのサンプルをまとめました。

# 前提条件
Visual StudioのNugetパッケージの管理から、「Newtonsoft.Json」をインストールしておく必要があります。
※Nugetについては[こちら](https://qiita.com/MetroOsamu/items/0b6f1aca575136b0aa16)も参照。

# 属性名について
本稿で登場する、JSONのデシリアライズを行う際に必要な属性についてまとめました。

### JsonObject
クラスがJSONオブジェクトとして扱われることを示します。

### JsonProperty
JSONのKeyと紐づけるための名前を明示的に指定できます。

# デシリアライズの例
## パターン1
### JSONデータの構成の説明

#### 最上位の階層
| Key名 | 説明 |
| ---- | ---- |
| MainA | KeyとValue (文字列) の要素が複数個格納されている |
| MainB | 文字列の値ひとつのみ |
| MainC | 中にKeyが3種類 (Name、Title、Values) が格納されている|

#### MainCの子階層
| Key名 | 説明 |
| ---- | ---- |
| Name | 文字列の値ひとつのみ |
| Title | KeyとValue (文字列) の要素が複数個格納されている |
| Values |KeyとValue (文字列) の要素が複数個格納されているのに加え、いくつかの要素がまとまっており配列になっている|

:::note
JSONは`{}`を使用して入れ子のようにすることができます。また配列は`[]`で囲まれています。
:::

### JSONデータ

```json
{
  "MainA": {
    "MainA-1": "あ",
    "MainA-2": "い"
  },
  "MainB": "う",
  "MainC": [
    {
      "Name": "え",
      "Title": {
        "TitleA-1": "お",
        "TitleA-2": "か",
        "TitleA-3": "き",
        "TitleA-4": "く",
        "TitleA-5": "け",
        "TitleA-6": "こ",
        "TitleA-7": "さ"
      },
      "Values": [
        {
          "ValuesA-1": "し",
          "ValuesA-2": "す",
          "ValuesA-3": "せ",
          "ValuesA-4": "そ"
        },
        {
          "ValuesA-5": "た",
          "ValuesA-6": "ち"
        }
      ]
    },
    {
      "Name": "つ",
      "Title": {
        "TitleB-1": "て",
        "TitleB-2": "と",
        "TitleB-3": "な",
        "TitleB-4": "に",
        "TitleB-5": "ぬ"
      }, 
      "Values": [
        {
          "ValuesB-1": "ね",
          "ValuesB-2": "の",
          "ValuesB-3": "は"
        }
      ]
    },
    {
      "Name": "ひ",
      "Title": {
        "TitleC-1": "ふ"
      }, 
      "Values": [
        {
          "ValuesC-1": "へ",
          "ValuesC-2": "ほ"
        }
      ]
    }
  ]
}

```

### データクラスの定義

```C#
    [JsonObject]
    public class JsonModel
    {
        [JsonProperty("MainA")]
        public Dictionary<string, string> MainA { get; set; }

        [JsonProperty("MainB")]
        public string MainB { get; set; }

        [JsonProperty("MainC")]
        public List<MainCModel> MainC { get; set; } = new List<MainCModel>();
    }

    public class MainCModel
    {
        [JsonProperty("Name")]
        public string Name { get; set; }

        [JsonProperty("Title")]
        public Dictionary<string, string> Title { get; set; }

        [JsonProperty("values")]
        public Dictionary<string, string>[] Values { get; set; }
    }
```


### デシリアライズ方法

```C#
    private JsonModel GetJsonModel()
    {
        try
        {
            string jsonStr;
            using (var sr = new StreamReader("Jsonファイルまでのパス", Encoding.GetEncoding("shift_jis")))
            {
                jsonStr = sr.ReadToEnd();
            }

            var deserializedData = JsonConvert.DeserializeObject<JsonModel>(jsonStr);

            return deserializedData;
        }
        catch(Exception ex)
        {
            // エラー処理等
        }
    }
```

## パターン2


#### 最上位の階層
| Key名 | 説明 |
| ---- | ---- |
| MainA | KeyとValue (文字列) の要素が複数個格納されているのに加え、いくつかの要素がまとまっており配列になっている |
| MainB | 中にKeyが2種類 (Names、Items) が格納されている |

#### MainBの子階層
| Key名 | 説明 |
| ---- | ---- |
| Names | KeyとValue (文字列) の要素が複数個格納されている |
| Items | 中にKeyが3種類 (Title、Values、Remark) が格納されている |

#### Itemsの子階層
| Key名 | 説明 |
| ---- | ---- |
| Title | 文字列の値ひとつのみ |
| Items | KeyとValue (文字列) の要素が複数個格納されているのに加え、いくつかの要素がまとまっており配列になっている |
| Remark | 文字列の値ひとつのみ |



### JSONデータ

```json
{
  "MainA": [
    {
      "MainA-1": "あ",
      "MainA-2": "い"
    },
    {
      "MainA-3": "う"
    },
    {
      "MainA-4": "え",
      "MainA-5": "お",
      "MainA-6": "か"
    }
  ],
  "MainB": [
    {
      "Names": {
        "NameA-1": "き",
        "NameA-2": "く"
      },
      "Items": [
        {
          "Title": "け",
          "Values": [
            {
              "ChildValuesA-1": "こ",
              "ChildValuesA-2": "さ",
              "ChildValuesA-5": "し"
            },
            {
              "ChildValuesA-3": "す",
              "ChildValuesA-4": "せ",
              "ChildValuesA-5": "そ",
              "ChildValuesA-6": "た",
              "ChildValuesA-7": "ち"
            }
          ],
          "Remark": "つ"
        },
        {
          "Title": "て",
          "Values": [
            {
              "ChildValuesB-1": "と",
              "ChildValuesB-2": "な",
              "ChildValuesB-3": "に",
              "ChildValuesB-4": "ぬ",
              "ChildValuesB-5": "ね"
            },
            {
              "ChildValuesB-6": "の",
              "ChildValuesB-7": "は",
              "ChildValuesB-8": "ひ"
            },
            {
              "ChildValuesB-9": "ふ",
              "ChildValuesB-10": "へ"
            }
          ],
          "Remark": "ほ"
        }
      ]
    },
    {
      "Names": {
        "NameB-1": "ま",
        "NameC-2": "み",
        "NameD-3": "む"
      },
      "Items": [
        {
          "Title": "め",
          "Values": [
            {
              "ChildValuesC-1": "も",
              "ChildValuesC-2": "や",
              "ChildValuesC-5": "ゆ"
            }
          ],
          "Remark": "よ"
        }
      ]
    }
  ]
}
```

### データクラスの定義

```C#
    [JsonObject]
    public class JsonModel
    {
        [JsonProperty("MainA")]
        public Dictionary<string, string>[] MainA { get; set; }

        [JsonProperty("MainB")]
        public List<MainBModel> MainB { get; set; }
    }

    public class MainBModel
    {
        [JsonProperty("Names")]
        public Dictionary<string, string> Names { get; set; }

        [JsonProperty("Items")]
        public List<ItemsModel> Items { get; set; }
    }

    public class ItemsModel
    {
        [JsonProperty("Title")]
        public string Title { get; set; }

        [JsonProperty("Values")]
        public Dictionary<string, string>[] Values { get; set; }

        [JsonProperty("Remark")]
        public string Remark { get; set; }
    }
```
### デシリアライズ方法
[こちら](#デシリアライズ方法)と同様。

## 補足
### シリアライズについて
デシリアライズ後のクラスを使用して、以下のようにシリアライズもできます。
```C#

    string jsonStr;
    using (var sr = new StreamReader("Jsonファイルまでのパス", Encoding.GetEncoding("shift_jis")))
    {
        jsonStr = sr.ReadToEnd();
    }

    // デシリアライズ
    var deserializedData = JsonConvert.DeserializeObject<JsonModel>(jsonStr);

    // シリアライズ
    jsonStr = JsonConvert.SerializeObject(deserializedData);  // json形式の文字列が取得できる (デシリアライズ前と同様の文字列)
```

# 終わりに
JSONは業務であまり触った経験がなかったので、自身の勉強を兼ねて記載してみました。
[パターン2](#パターン2)の方はJSONファイルのみをみると少し複雑そうでしたが、データクラスにすると意外とすっきりとおさまりました。
[xmlのデシリアライズの場合](https://qiita.com/MetroOsamu/items/af0bb2cd1275662b29d5)と比べると、やや属性やクラス構成が単純で扱いやすい？ような印象をもちました。
※あくまで個人的な印象です。