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

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

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

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

Q&A

解決済

2回答

7897閲覧

C#でプロパティを再帰的に取得したいです。

cancat

総合スコア313

C#

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

0グッド

0クリップ

投稿2016/10/10 13:34

プロパティを再帰的に取得したいです。
こんにちは。 いつもたいへんお世話になっております。
Windows10でアプリケーションを開発しています。
Visual Studio 2015 Communityを使っています。

###実現したいこと
プロパティを再帰的に取得したいです。
複雑な構造のJSONをパースした場合、まずとりあえず一覧で見てみたい、と考えました。
かんたんにlogする方法を教えてください。いまは手動で書いていますが、"項目名=" + 項目内容のようなlogを簡単に出力できませんか?

###該当のソースコード

C#

1 public static string ReadJSON(string jsonstring) { 2 string log = ""; 3 try { 4 List<ChatWorkTaskClass> cwtasks = JsonConvert.DeserializeObject<List<ChatWorkTaskClass>>(jsonstring); 5 foreach (ChatWorkTaskClass task in cwtasks) { 6 log += "●" + task.limit_time + task.body + "\r\n"; 7//ここで、"項目名=" + 項目内容のようなlogを作りたい。 8 } 9 } 10 catch (Exception exception) { 11 string error = exception.Message; 12 } 13 return log; 14 } 15 } 16} 17 18public class ChatWorkTasks { 19 public List<ChatWorkTaskClass> ChatWorkProperty { get; set; } 20} 21 22public class ChatWorkTaskClass { 23 public int task_id { get; set; } 24 public Account account { get; set; } 25 public Account assigned_by_account { get; set; } 26 public int message_id { get; set; } 27 public string body { get; set; } 28 public int limit_time { get; set; } 29 public string status { get; set; } 30} 31

C#

1foreach (ChatWorkTaskClass task in cwtasks) { 2 PropertyInfo[] infos = task.GetType().GetProperties(); 3 foreach (PropertyInfo info in infos) 4 log += info.Name + "\t" + info.GetValue(task, null) + "\r\n";

で1階層はできました。自動で階層をたどるようにしたいです。

###補足情報(言語/FW/ツール等のバージョンなど)
Microsoft Visual Studio Community 2015
Version 14.0.25424.00 Update 3
Microsoft .NET Framework
Version 4.6.01038

インストールしているバージョン:Community

Visual C# 2015 00322-20000-00000-AA575
Microsoft Visual C# 2015

です。
よろしくお願いします。

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

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

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

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

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

guest

回答2

0

こんにちは。

infosをforeachで枚挙する時、infoに対応するフィールドの値を取ってきます。
それがクラスだったら、taskに行っている処理と同じ処理を再帰的に行います。
それがコンテナだったら、cwtasksに行っている処理と同じ処理を行います。(配列処理は再帰しない方が簡単と思います。型が異なるのでややこしくなりそうです。)

イメージを示すため再帰を展開した形でポイントだけ書いてみました。(ビルドしてません。こんなに長いソースは確実にバグってますが、主旨は掴めると思います。)

ところで、C#のstringはプリミティブではないので要注意です。

C#

1foreach (ChatWorkTaskClass task in cwtasks) 2{ 3 PropertyInfo[] infos = task.GetType().GetProperties(); 4 foreach (PropertyInfo info in infos) 5 { 6 Type type=info.PropertyType ; 7 if ((type.IsPrimitive) || (type == typeof(string))) 8 { 9 log += info.Name + "\t" + info.GetValue(task, null) + "\r\n"; 10 } 11 else if (type.IsArray) 12 { 13 配列の処理 14 } 15 else 16 { 17 // 下記2行は、object member=info.GetValue(task, null);でも良いかも知れません。 18 Type parentType = task.GetType(); 19 object member=parentType.InvokeMember(info.Name, BindingFlags.GetField, null, task, null); 20 21 PropertyInfo[] infos = member.GetType().GetProperties(); 22 foreach (PropertyInfo info in infos) 23 { 24 続く 25 } 26 } 27 } 28}

インデントも付けないと見にくいですし、そこそこ手間がかかると思います。
もっとお手軽な方法もあります。
単純にPrettyPrintなJsonでログへ出力するのです。元のJsonではなく読み取ったJsonなのでログとしても使えると思います。

投稿2016/10/10 14:27

編集2016/10/11 02:43
Chironian

総合スコア23272

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

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

cancat

2016/10/11 03:22

ありがとうございます。 なんと。 Propertiesを使えるようになって使ってみましたが、PrettyPrint? で出力できるんですね。それは簡単そうです。聞いていよかったです。 PrettyPrintってなにですか?
Chironian

2016/10/11 03:25

人が見やすく整形して出力することです。 Jsonは改行やインデントを付ける必要はありませんので1行で全てのデータを送ることもできます。効率を重視する時はそのようにしますが、とても人が読めるものではなくなります。
cancat

2016/10/11 03:33

なるほど。ありがとうございます。 おっしゃるとおり、JSONだらだらしていて読めなくて、\uとかも出てきて、途方に暮れてました。 一歩一歩ですが先に進んでいます。 感謝です。
guest

0

ベストアンサー

クラスのプロパティをリフレクションを使って取り出す方法は非常に重いのであまりおすすめできません。

json.netですよね?
であればクラスにしてからプロパティを読み取るなんてまどろっこしいことしなくても直にjson文字列から処理できますよ。
以下のコードで全プロパティ(深い階層含む)を取れます。

C#

1string json; // JSON文字列 2var root = (JContainer)JToken.Parse(json); 3var log = root.DescendantsAndSelf() 4 .OfType<JProperty>() 5 .Select(p => p.Name + ": " + p.Value) // 「task_id: 10」という風になる 6 .ToArray();

階層別に格納したい等もいくらでも対応できるので、いろいろ調べてみると今後もなにかと応用がききます。
公式ドキュメントは参考になるので是非読んでみてください。全部英語ですが、ほとんどコードなのできっと問題なく読めます。
Querying JSON with LINQ

投稿2016/10/11 01:37

編集2016/10/11 01:55
ishi9

総合スコア1294

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

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

cancat

2016/10/11 03:31

ひゃー。これは楽です。 微妙にほしい形とちがう(階層がある場合は階層部分のValueはいらない)のですが、この手軽さはすごいです。 コードのシンプルさでこちらをベストに。
cancat

2016/10/11 07:29

うーむ。 var root = (JContainer)JToken.Parse(jsonstring); var logarray = root.DescendantsAndSelf() .OfType<JProperty>() .Where(p => p.Value.Type != JTokenType.Object)       .Select(p => "●" + p.Name + ": " + p.Value) // 「task_id: 10」という風になる .ToArray(); foreach (var a in logarray) log += a + "\r\n"; ではうまくいかなかったです。
ishi9

2016/10/11 07:34

あれ、Objectじゃなかったかな・・・ Select(p => "●" + p.Name + ": " + p.Value.Type.ToString()) あるいは Select(p => "●" + p.Name + ": " + p.Type.ToString()) とかでそれぞれのプロパティのTypeを出力できると思うので、 それを見比べたら不必要なものを取り除けるかもしれません。 すいません、ちゃんと確認したことないので当てずっぽうです。
cancat

2016/10/11 08:18

了解です。ありがとうございます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問