質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.47%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

1回答

2251閲覧

[C#] 入れ子になったJsonをデシリアライズしたい

XnyantamaX

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

0クリップ

投稿2022/09/06 04:26

Json

1{"content_type": "user", "content": {"birth": "2022-09-03","name": "panda", "age": 5} 2{"content_type": "comment", "content": {"timestamp": "2022-09-05","title": "Hello", "content": "Nice to meet you"}

CSharp

1public class Log 2{ 3 public string? content_type; 4 public User? user; 5 public Comment? comment; 6} 7 8public class User 9{ 10 public DateTime birth; 11 public string? name; 12 public int age; 13} 14 15public class Comment 16{ 17 public DateTime timestamp; 18 public string? title; 19 public string? content; 20}

上記のJsonをLog型にデシリアライズしたいのですが、"content_type"キーによって、入れ子になった部分をUser型にデシリアライズするか、Comment型にデシリアライズするかを分けたいです。

CSharp

1public class Log 2{ 3 public string? content_type; 4 //public User? user; 5 //public Comment? comment; 6 public <User | Comment> content //こんな文法ない 7}

また、このようにUserとCommentを共用体のようにしたいです。

このような機能を実装するためにはどうすればよいでしょうか。Unityを用いた開発を前提としています。ご回答よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2022/09/07 05:53

質問者さん、無言ですが、回答したのでそれに対するフィードバックを返してください。役に立った/立たなかったぐらいはすぐに返せるのでは? 役に立たなかったならどこがダメかを書くとより期待に近い回答が出てくるかも。とにかく無言は NG です。
guest

回答1

0

"content_type"キーによって、入れ子になった部分をUser型にデシリアライズするか、Comment型にデシリアライズするかを分けたいです。

まず JSON 文字列から content_type の値を取得して、それが "user" なのか "comment" なのかを調べて、前者なら User 型に、後者なら Comment 型にデシリアライスしてはいかがですか?

"user" なのか "comment" なのかを調べる方法は以下の記事を見てください。

JSON 文字列から指定した name の value を取得
http://surferonwww.info/BlogEngine/post/2021/02/11/find-value-by-name-in-json-string.aspx


【追記】

具体例を書いておきます。

上の回答に「"user" なのか "comment" なのかを調べる方法は以下の記事を見てください」と書きましたが、質問に書いてある JSON 文字列 2 つのパターンだけで決まりであれば、もっと簡単にできますので以下にその方法を書きます。

質問の JSON 文字列は末尾の } が抜けているという間違いがありますがそこは直して、以下の 2 つのパターンだけ考えればよいと理解します。

{ "content_type": "user", "content": {"birth": "2022-09-03","name": "panda", "age": 5} } { "content_type": "comment", "content": {"timestamp": "2022-09-05","title": "Hello", "content": "Nice to meet you"} }

まず、2 つのパターンどちらにもデシリアライズできるクラス定義を作り、これにデシリアライズします。

public class Rootobject { public string? content_type { get; set; } public Content? content { get; set; } } public class Content { public string? birth { get; set; } public string? name { get; set; } public int age { get; set; } public string? timestamp { get; set; } public string? title { get; set; } public string? content { get; set; } }

System.Text.Json のデシリアライザを使うと以下のようになります。

using System.Text.Json; string jsonString1 = @"{ ""content_type"": ""user"", ""content"": {""birth"": ""2022-09-03"",""name"": ""panda"", ""age"": 5} }"; string jsonString2 = @"{ ""content_type"": ""comment"", ""content"": {""timestamp"": ""2022-09-05"",""title"": ""Hello"", ""content"": ""Nice to meet you""} }"; Rootobject? rootobject1 = JsonSerializer.Deserialize<Rootobject>(jsonString1); Rootobject? rootobject2 = JsonSerializer.Deserialize<Rootobject>(jsonString2);

デシリアライズの結果、JSON 文字列の content の中に Content クラスのプロパティに該当するものがない場合は string? 型は null に int 型は 0 になります。

上の rootobject1, rootobject2 を質問にある Log, User, Comment クラスに詰め替えます。具体例は以下のサンプルコードを見てください。詰め替える際に content_type が "user" なのか "comment" なのかを調べて処理しています。

static Log? CreateLog(Rootobject? rootObj) { if (rootObj == null) { return null; } if (rootObj.content_type == "user") { var log = new Log() { content_type = rootObj.content_type, user = new User { birth = ((Func<string?, DateTime>)((s) => { DateTime dateValue; DateTime.TryParse(s, out dateValue); return dateValue; }))(rootObj.content?.birth), name = rootObj.content?.name, age = (rootObj.content != null)? rootObj.content.age : 0 }, comment = null }; return log; } else if (rootObj.content_type == "comment") { var log = new Log() { content_type = rootObj.content_type, user = null, comment = new Comment { timestamp = ((Func<string?, DateTime>)((s) => { DateTime dateValue; DateTime.TryParse(s, out dateValue); return dateValue; }))(rootObj.content?.timestamp), title = rootObj.content?.title, content = rootObj.content?.content } }; return log; } else { return null; } }

結果は以下のようになります。

イメージ説明

投稿2022/09/06 09:26

編集2022/09/07 03:12
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.47%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問