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

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

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

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

JSON

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

Unity

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

Q&A

解決済

3回答

9396閲覧

Unityのc#でJsonのデータをデシリアライズしたいのですがうまくできずに困っております

hazemi94

総合スコア7

C#

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

JSON

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

Unity

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

API

APIはApplication Programming Interfaceの略です。APIはプログラムにリクエストされるサービスがどのように動作するかを、デベロッパーが定めたものです。

0グッド

0クリップ

投稿2017/03/27 23:03

###前提・実現したいこと
Unityのスクリプト(c#)上で、Json形式のstring型の変数をapiとしてGetして受け取り、その受け取ったstring型の変数をあらかじめ作っておいたクラスに代入し、リスト化したいと思っております。

具体的には、apiとして以下のJson形式の文字列を受け取るので、

{"player_data":[{"id":1,"name":"Bob","point":42},{"id":2,"name":"Mary","point":26},{"id":3,"name":"Mike","point":63},{"id":4,"name":"Sayaka","point":53},{"id":5,"name":"Json","point":64}]}

このデータを以下のクラスを用いて

public class PlayerListData : MonoBehaviour { public List<PlayersListDetail> player_list { get; set; } public class PlayersListDetail { public int id { get; set; } public string title { get; set; } public int point { get; set; } } }

以下のようにPlayer_listをインスタンス化した変数にPlayerListDatail型のデータを追加するようにしたいと思っております。

idnamepoint
1Bob42
2Mary26
3Mike63
4Sayaka53
5Json64

なにぶんJsonデータをUnityで扱うこと自体が初めてで、c#でのListやDictionaryの機能も経験が浅いです。
様々なJsonデータをc#にデシリアライズするサイトを見たのですが、API内の初めの"player_data"の部分を取り除くのがやっとだったり、できたと思っても型が違うと怒られて何日もここの実装に詰まっているので質問させていただきました。

今回質問したい内容は以下の2つです
0. 上のような仕様を満たすようなdecodeJsonクラス(途中までは下のソースコードに書いてあります)をどう書いていけば良いのでしょうか?(ヒント(?)が欲しいです)
0. 下のソースコード内に登場するIList, IDictionaryとはList, Dictionaryとどのように違うのでしょうか?

###途中まで考えて見たソースコード

using System.Collections; using System.Collections.Generic; using UnityEngine; using MiniJSON; public class decodeJson : MonoBehaviour { [SerializeField] private string url; // Use this for initialization void Start () { StartCoroutine(Get(url)); } IEnumerator Get (string url) { // 送信開始 WWW www = new WWW(url); yield return www; PlayerListData playerListData = new PlayerListData(); // 成功 if (www.error == null) { string change = "[" + www.text + "]"; IList namesList = (IList) Json.Deserialize(change); foreach (IDictionary name in namesList) { var hoge = tag["player_data"]; // 上でplayer_dataの部分は取り除けていると思っています //IList tagsmiddleList = (IList) Json.Deserialize(hoge); /*上のコメントを外すと error CS1503: Argument `#1' cannot convert `object' expression to type `string' といったエラーが表示されます */ foreach (var fuga in tagsmiddleList) { // jsでしたら tag["player_data"][0]といった形で取れると思うのですが… } } } // 失敗 else{ Debug.Log("Failed"); } } }

###試したこと
[Unity][MiniJSON]JSONデータを読み込む
上のサイトを用いて書きました

また、上記以外のサイトを使って書いてみるといったようなことも行ってみました。

###補足情報(言語/FW/ツール等のバージョンなど)
Unity : 5.5.0f3
使用言語 c#

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

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

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

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

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

guest

回答3

0

ベストアンサー

Unity は全く知らないので、C# での JSON 文字列の逆シリアル化ということに限ってレスします。

C# のクラス定義が違うのではないですか?

質問にアップされていた JSON 文字列の場合は以下のようになると思うのですが。

public class RootObject { public List<PlayerData> player_data { get; set; } } public class PlayerData { public int id { get; set; } public string name { get; set; } public int point { get; set; } }

【追伸】

「JSON 文字列」⇒「C# のクラス定義」の変換サービスがあるので使ってみてください。

json2csharp
http://json2csharp.com/

【追伸2】

「C# のクラス定義が違うのではないですか?」とか言っておいてハズレだったら何ですので、Json.NET を使って検証してみました。(MiniJSON というのは持ってないのでそれでどうやるかは分かりません)

Json.NET なら上に書いたクラス定義で逆シリアル化できることは確認できました。以下のコードを見てください。

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; namespace JsonNETSample { class Program { static void Main(string[] args) { string json = @"{""player_data"":[ {""id"":1,""name"":""Bob"",""point"":42}, {""id"":2,""name"":""Mary"",""point"":26}, {""id"":3,""name"":""Mike"",""point"":63}, {""id"":4,""name"":""Sayaka"",""point"":53}, {""id"":5,""name"":""Json"",""point"":64}]}"; RootObject root = JsonConvert.DeserializeObject<RootObject>(json); foreach (PlayerData player in root.player_data) { Console.WriteLine("id:{0}, name:{1}, point:{2}", player.id, player.name, player.point); } /* 結果は: id:1, name:Bob, point:42 id:2, name:Mary, point:26 id:3, name:Mike, point:63 id:4, name:Sayaka, point:53 id:5, name:Json, point:64 */ } } public class RootObject { public List<PlayerData> player_data { get; set; } } public class PlayerData { public int id { get; set; } public string name { get; set; } public int point { get; set; } } }

というわけで・・・

1.上のような仕様を満たすようなdecodeJsonクラス(途中までは下のソースコードに書いてあります)をどう書いていけば良いのでしょうか?(ヒント(?)が欲しいです

MiniJSON ではなく Json.NET を使った例ですが、上のコードを見てください。

2.下のソースコード内に登場するIList, IDictionaryとはList, Dictionaryとどのように違うのでしょうか?

IList, IDictionary など、頭に I がつくのはインターフェイスです。インターフェイスを継承したクラスはインターフェイスで定義されるメソッドを必ず実装するというルールになっています。

List<T>, Dictionary<TKey, TValue> はクラスです。それぞれ IList, IDictionary を継承しています。

投稿2017/03/27 23:48

編集2017/03/28 01:01
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

hazemi94

2017/03/28 08:20 編集

1. やはり2つのクラスに分けた方が良いのですね。特にMiniJsonにこだわっているわけではないので、Json.NETを使わせていただきたいと思います。 上のコードを見ると apiの"player_data"の部分はRootObject型の変数rootには含まれていないように見えるのですが、これはなぜでしょうか? 今回、json形式のstring型の変数はAPIからgetする形で受け取るので、 foreach (PlayerData player in root.player_data) { Console.WriteLine("id:{0}, name:{1}, point:{2}", player.id, player.name, player.point); } の.player_dataといったように書くことができません…。 どうしたら良いでしょう?? 2. インターフェースを使っているということは、単純にList, Dircectionといったインターフェースを継承したクラスを使ってインスタンス化してもいいという解釈で良いのかと思ったのですが、これは正しいのでしょうか?
退会済みユーザー

退会済みユーザー

2017/03/28 08:16 編集

1. 質問の意味が分かりません。RootObject クラスのプロパティとして PlayerData オブジェクトのコレクションを設定・取得する player_data が定義してあります。root は JSON 文字列を逆シリアル化して生成した RootObject オブジェクトへの参照なので、root.player_data で PlayerData オブジェクトのコレクションを設定・取得できるということなのですが。それにどこか不明なところがありますか?
退会済みユーザー

退会済みユーザー

2017/03/28 08:25

2. これも質問の意味が分かりません。インスタンス化できるのはクラスであって、インスタンス化にインターフェイスというのは出てこないのですが。クラスのインスタンス化と、それへの参照を保持する変数の型をインターフェイス型にするのは別の話なのですが。
hazemi94

2017/03/28 08:29

すみません.player_dataを見落としていたため、 apiの"player_data"の部分はRootObject型の変数rootには含まれていないように見えるのですが、これはなぜでしょうか? に対しては理解できました!申し訳ございませんでした。 しかしapiでgetする形でtextデータを得るので、root.player_dataと書いてある部分を".player_data"と書くことができません。 同じように、APIの最初にある"player_data"は受け取り先によっては名前が変わることも(その後ろのid, name, pointの部分は変わりません)あり、foreachのinの後ろの部分が回答していただいた通りには書けないのですが、どうすれば良いでしょうか?
退会済みユーザー

退会済みユーザー

2017/03/28 08:40

JSON 文字列の "player_data" は変わると言ってます? そういうことは後出ししないで、一番最初の質問に書いておきましょう。 JSON 文字列の形式がどういう規則になっているか不明ですが、正規表現なり String クラスのメソッドを使うなりして [ から ] の部分を取り出して、それを逆シリアル化すればいいのでは?
hazemi94

2017/03/28 08:56

後出しの件に関しましては申し訳ありません。 2の質問に関しましては、私はまだインターフェースのことをきちんと理解できてないと思いましたので、自分でもう少し考えてみたいと思います。
guest

0

ここだけが問題なのかどうかわかりませんが、取りあえず tag["player_data"]string じゃないと思うのでキャストしてみたらどうでしょう?

Json.Deserialize((string)hoge);

投稿2017/03/27 23:28

Zuishin

総合スコア28660

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

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

hazemi94

2017/03/28 07:40

私も1回そう思ってキャストして見たのですが、 InvalidCastException: Cannot cast from source type to destination type. decodeJson+<Get>c__Iterator0.MoveNext () と型おかしいと怒られてしまうのです…。 ということは、tag["player_data"]はそもそもstring型かもしくはキャストできない型だと思われます。 tag["player_data"]がどういう型か知れれば、キャストできない理由もわかるのですが…
guest

0

もう既に解決済みですがもう少し簡単にできるので書きます。

Unity 5.3からUnity標準でJsonが扱えるようになりました。

よって

csharp

1[Serializable] 2public class PlayerDataResponse { 3 public PlayerData[] player_data; 4} 5 6[Serializable] 7public class PlayerData { 8 public int id; 9 public string name; 10 public int point; 11}

このようなクラスを作り

csharp

1PlayerDataResponse response = JsonUtility.FromJson <PlayerDataResponse> (json);

とすれば簡単にデシリアライズすることができます。

もしListにしたい場合は上記のコードの後に

csharp

1List<PlayerData> pdList = new List<PlayerData> (); 2pdList.AddRange (response.player_data);

とすれば良いのではないでしょか。

投稿2017/03/31 15:36

nobushiueshi

総合スコア60

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問