以下のような多段構造をした構造体を定義しました
lang
1public class ListModel 2{ 3 public Dictionary<string, string> A = new Dictionary<string, string>(); 4 public Dictionary<string, string> B = new Dictionary<string, string>(); 5 public Dictionary<string, Dictionary<string, string>> C = 6 new Dictionary<string, Dictionary<string, string>>(); 7 public Dictionary<string, List<Dictionary<string, string>>> D = 8 new Dictionary<string, List<Dictionary<string, string>>>(); 9ring, object>(); 10public Dictionary<string, object> dic = new Dictionary<string, object>(); 11// コンストラクタ 12 public LayoutModel(){ 13 this.dic = new Dictionary<string, object> { 14 {"A", A}, 15 {"B", B}, 16 {"C", C}, 17 {"D", D} 18 }; 19 } 20}
上記の構造体を以下のよう処理で取扱いたいと思っています。
lang
1// この返却値指定もおかしいですよね?( 2public ListModel Main(){ 3 4 ListModel list = new ListModel(); 5 List<string> KeyList = {"A","B","C","D"}; 6 7 foreach( string ListKey in KeyList ) 8 { 9 // エラーが出ます。。。当たり前ですよね。 10 list.dic[ListKey].Add( ListKey, "テストです" ); 11 } 12 13 // ここの返却値の型の指定の仕方もわかりません。(ListModel.dic を返したいです) 14 return list; 15}
何がやりたいの?という話なのですが、
画一的な構造ではなく、様々な多段構造をもつハッシュテーブルを
一定のルールに従い本処理で取扱いたいのです。
※出現したkeyによってif or switch 等で条件分岐するような泥臭い方法は極力行いたくない
C#(OR 型の制約がある程度厳密な言語で普段開発される方)は、こういったケースの場合
どのような実装方法(型定義も含めて)で、こういった問題をクリアするのでしょうか?
自分は、PHPから入ったので連想配列辺りのこの辺の処理はあまり意識して組んだことがありません。(データ生成後のアクセスのしやすさは考慮しますが、データ生成の時点では特に型・構造は意識しなくてよいので)
技術的な方法でこういった問題を解決する事ももちろん知りたいのですが、
漠然と感じているのは、そもそもの設計思想だと思っています。
そういった部分も含めて言及・ご意見頂けると大変ありがたいです。
一応、上記処理を利用して作るデータのイメージを掲載します。
lang
1dic: { 2 A: { 3 A-DATA: "123" 4 } 5 B: { 6 B-DATA-1: "B TEST" 7 B-DATA-2: "B 2 TEST" 8 } 9 C: { 10 C-1-DATA: { 11 C-DATA-1: "hogehoge" 12 } 13 } 14 D: { 15 A-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}] 16 B-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}] 17 C-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}] 18 } 19}
追記:
質問内容に記載したデータをどのようにシリアライズするかどうかはわかっています。
JSONがどうとか、SOAPだXMLだとかの質問をしているわけではないです。
以下の内容がわかれば知りたいです。
・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない
出来るのであれば出来る方法を出来ないのであれば、こういったニーズが発生した場合どういう風に対処するのかが知りたいです。
自分が、コメントに対してJSONで利用すう前提という事を記載してしまったのがいけないのですが
JSONでデータ通信は問題なく出来ていますので、その辺への言及は大丈夫です。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/05/11 11:02

回答13件
0
自己解決
投稿からかなり期間が経過してしまいましたが、
様々な方のご意見を受けて自分なりに問題の解決出来たので
簡単にですが実現方法を掲載しておきます。
1.データ構造をクラス化して対応しました
データ構成もですが、主に各々の階層へpushするメソッドを準備しました。
2.データの準備の順番を見直しました
最初、php的な考え方が抜け切れておらず、最初に最上位にあたるハッシュを定義した上で
二段階目の要素へデータを追加し続けるという方法で実装していたのですが、
要素[A・B・C・D]に格納する予定のハッシュを先に構築し、全ての要素を
準備した後に最上位のハッシュへ各生成したハッシュを格納する事で対応しました。
多段階層をもつハッシュを最初に定義した + その階層へのアクセス方法を
カプセル化できていなかったので、想定している動きが実装出来なかったという事でした。
結果的には、もっと効率が良かったりする方法もあるかと思いますが
自分としては、最低限実現したかった方法が実装できたので満足しています。
また、多くの方に様々なご意見を頂きまして色々な部分で勉強になりました。
特に質問投稿初期からご意見を再三に渡り頂きました
Tak1wa 様
katzC4ISR 様
haru666 様
ありがとうございました。
投稿2015/06/17 15:52
総合スコア87
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
見も蓋もない話ですが、まずはC#の一般的なコーディングルールを学ぶ方が妥当だと思います。
C#ではこのようにDictionaryをネストしないのが普通です。
Jsonに一定のルールを決定することがC#ではクラスの定義に相当します。
Jsonの連想配列は型の宣言こそありませんが、皆さん型自体は無意識ながら決めていると思います。
やれこのデータ型は文字列である、数値である、別のオブジェクトである、ということを分かって使っているはずです。
これを先に宣言するのがC#です。
C#で連想配列を扱うのは、連想配列でなくてはならない場合のみです。
クラス⇔Json の変換にはJson.NETを使用するといいと思います。
まずC#のクラスについて勉強し、その後Json.NETの利用方法を確認してみてください。
Json.NETの利用方法は、C#とJsonの違いを教えてくれると思います。
投稿2015/05/12 01:24
編集2015/05/12 01:33総合スコア1593
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
なるほど,アプローチは2つあると思います
- DBから読み込むデータを受け取るエンティティクラスを定義する.このエンティティをDataContract~等でJSON文字列化する
- そうではなくて,DBから読み込むデータ構造が多様なので,逐一エンティティクラスを定義したくない,そこでJavaScriptのように連想配列と配列を組み合わせた汎用的なエンティティクラスがあればよい.
2)のアプローチの場合は,どうすればいいか?ということですね?
これはですね.私もそう思います.
Windows.Data.Json クラス
https://msdn.microsoft.com/ja-jp/library/windows/apps/br229889.aspx
残念ながらこのクラスをどうやって使えばいいかが,どうしてもわかりませんでした.
Windows8や2012では使えるようなのですが...
なので,自分で実装しました.Windows.Data.Jsonの仕様のように,
JSONValueのためのインターフェースを定義して(プリミティブ値,配列,連想配列すべてを表す)
インターフェースを実装したJSONObject,連想配列を持つDictionary<String, JSONValue>
JSONArray,配列を持つList<JSONValue>
たとえば,{"Key":"Value"} の場合は,JSONObject.Add(”Key”,"Value")
{"Key":["Value"]} の場合は,JSONObject.Add(”Key”,JSONArray.Add("Value"))
["Key1":{"Key2":Value}] の場合は,JSONArray.Add("Key1", JSONObject.Add(”Key2”,Value)
こういった形で使いました.
投稿2015/05/12 00:49
総合スコア66
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
一つのDictionaryにValueやネストしたDictionaryを入れ、複雑な構造を作りたいということですか?
その場合、最も適切な方法は、Dictionary<string, dynamic>でDictionaryを宣言し、各要素の追加を行います。
ネストさせるDictionaryも全て<string, dynamic>で作成する必要があります。
インテリセンスが効かなくなる問題はありますが、ネストしたDictionaryに値を追加するときもAddを使うだけで済みます。
動的な構造変更をしていることになるので、型が一致しているかどうかを管理するのはプログラマの責任となります。
lang
1var dict = new Dictionary<string, dynamic>(); 2dict.Add("A", new Dictionary<string, dynamic>()); 3dict.Add("B", new Dictionary<string, dynamic>()); 4dict.Add("C", new Dictionary<string, dynamic>()); 5 6dict["A"].Add("1", "ABCDE"); 7dict["A"].Add("2", "FGHIJ"); 8dict["B"].Add("x", "test"); 9 10dict["C"].Add("AAA", new Dictionary<string, dynamic>()); 11dict["C"]["AAA"].Add("1", "hogehoge"); 12 13var value = dict["A"]["1"]; // -> value = "ABCDE"
静的な型付けを持つC#で構造の違うオブジェクトを同様に扱いたい場合はobjectかdynamicを使うか、ジェネリックな入れ物を作成する方法で対応できます。この用途で使える入れ物の作成方法はここには書きませんが、結局は型消去をするので値の取り出しにキャストが必要になり、あまり有用ではありません。
投稿2015/05/16 06:47
総合スコア4275
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
エラーが出るのは宣言された型と入力されるデータに互換性がないからです。
試しに「テストです」の部分を null に変えたらうまくいくのではないですか?
AおよびBのデータ型は文字列なので、文字列である「テストです」は代入できます。
CおよびDのデータ型はDictionary<string, string>なので、文字列は代入できません。
多段構造とかハッシュテーブルとか言う以前の問題だと思います。
なんでも代入できる変数が欲しければ、object あるいは dynamic を使うべきでしょう。
投稿2015/05/15 03:34
総合スコア28673
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
うーむ、難しい話になってきましたね。
・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない
まずJSONのことはキッパリ忘れますね。
上記をやりたいだけであれば、
Dictionary<string, IDictionary>にしてやれば詰め込めます。
ただし再帰的にDictionaryまたはValueとして扱いたいのでしょうから、
以下のようにDictionary自体を作成して、object型の部分をカスタムクラス内で吸収してやれば実装自体は出来る気がしてます。
lang
1public class DictionaryEx : Dictionary<string, object>, IDictionary<string, DictionaryEx>, IDictionary<string, string>
↑頓珍漢なこと言ってました。試してみましたがダメっぽかったです。
ここからJSONを前提とした話にちょっと戻ります(お気に障ったらすみません)
質問内容に記載したデータをどのようにシリアライズするかどうかはわかっています。
私が勘違いしていたら申し訳ないのですが、皆さんが仰っているのでは逆の話で、
クライアントから受け取ったJSON文字列を、ASP.NET側でフレームワークを用いてデシリアライズしてやれば、
Dictionary型をネストするぐらいなら通常はクラス自体をネストします。
とするだけで簡単に出来るしスマートだし変更にも強いよ、と言っているのだと思います。
質問文の最初に
lang
1foreach( string ListKey in KeyList )
とありましたが、ひょっとしてループでぐるぐるとJSON⇔POCOの変換をかけようとしていませんか?
↑ これも私の検討違いかも…。質問者さんはデシリアライズのことについては触れてませんでしたね。
本回答は無視してください。失礼しました。
投稿2015/05/12 10:28
編集2015/05/12 10:54総合スコア4791
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
これ同じ事考えていろいろ試したことがあるのですがデータクラスはobjectで定義しておいて処理を行うメソッドをジェネリックにして使うのが私の限界でした。
objectを型パラメータで指定された型にキャストして、ごにょごにょ処理をすると。
型制約とかで「一定のルール」の範囲を絞ることも出来ると思います。
ただ、型増えるわ共通化しすぎていろんなところで依存しまくるわ(設計が悪いだけかもしれないけど)・・・・これだったらLinqつかっちゃったほうが早いなぁと今は思ってます。。。
最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない
リフレクションで呼んであげれば良いんじゃないかな
ttp://dobon.net/vb/dotnet/programing/typeinvokemember.html
イメージ的にはアンマネージDLLのメソッド使う感じでメンバを呼び出す感じ。
当然使われる側の正確なメソッドの定義を使う側が知っている必要があります。
総じて「どんな構造であるか使う側が知らないでその構造には触れない」ってのが一般論かと。
究極的には上のリフレクションでメンバ名を「文字列」で扱うことが出来るんで、動的に構造を解析して操作することも出来なくはないと思いますが・・・・まぁ業務アプリでそんなの作ったら普通怒られますよね・・・
以上
投稿2015/05/12 09:39
編集2015/05/12 09:40総合スコア85
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない
this.dic = new Dictionary<string, object> {
ここがobject型なので,値を取り出したところでそのままでは構造の違うハッシュには格納してくれませんね.
すみません,元のコードに戻って
list.dic[ListKey].Add( ListKey, "テストです" );
の時に、ABCDそれぞれどのような動きをさせたいですか?
ここから再開いたしましょう.たとえば,このAddが成功したとして,
ABCDはどのように変化してほしいですか?
投稿2015/05/12 08:23
総合スコア66
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
汎用的なツリー構造の型付きデータを扱いたいという要望なら、
XMLとSOAP通信を行うのが一般的だと思います。
XMLの仕様は DTDや XML Schema やら RELAXやらで定義します。
私企業・公的機関 を超える標準データ交換規約ではよく用いられますね。
例えば メタボ健診のデータの
http://www.mhlw.go.jp/bunya/shakaihosho/iryouseido01/info02i.html
とか、
ヤマト運輸の送り状データなんて一風変わったものも
http://www.kuronekoyamato.co.jp/newb2/help/manual/manual_sosa/16_exchange/exchange_01.html
とか。
で、こういう DTDやら XML Schema のスキーマをもらえれば、
動的にXMLをパースできてしまうので、実質上あらゆる階層化データを
扱えることになります。SOAPなんかはそのための通信規格ですね。
単にブラウザとサーバで同じデータモデルを扱いたい、ということであれば、
サーバ側のクラス定義をそのまま ブラウザ側とやりとりする、という
仕組みはいくつもありますね。
ASP.Netなら 古くは AJAX Extensions から、
今は ASP.Net MVCで提供されているんじゃないでしょうか。
たとえば、いいまとめ記事があります。
http://qiita.com/kazuhisam3/items/94542f6d7ccf3acca41c
ただ、他の回答者も指摘されているとおり、サーバ側できちんとモデル定義をすることは必要です。
それは C#だから 型付き言語だからというのではなく、PHPでもそうだったはずですけどね。
投稿2015/05/12 02:51
総合スコア200
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

0
どうも,改めまして.
C#でJSONを扱うには,幾つか選択肢があります.以下,Webに出回っている情報のポインタになりますが,ご紹介いたします.
おおむね
http://www2.hatenadiary.jp/entry/2013/12/14/030112
によくまとめられています.
概要をお話いたしますと,
0. ちゃんとJSONを扱いたい > Json.NET, DynamicJSON
0. ある程度固定の情報のJSONを扱いたい > System.Runtime.Serialization.Json(JsonReaderWriterFactory, DataContractJsonSerializer)や, System.Web.helpers.JsonやSystem.Web.Extentions.dllのJavaScriptSerializerを使う
ということのようです.
.NET Framework < 3.5
Json.NET
http://www.newtonsoft.com/json
Json.NET/デシリアライズ支援サイト
http://json2csharp.com/
.NET Framework 3.5 から
System.Service.Modelを参照に追加しよう.
System.Runtime.Serialization.Json JsonReaderWriterFactory DataContractJsonSerializer http://msdn.microsoft.com/ja-jp/library/bb412179(v=vs.110).aspx http://jsontodatacontract.azurewebsites.net/ DataContractJsonSerializerで不定形のJSONデータを読み込む
.NET Framework 4.0 から
DynamicJSON
http://neue.cc/2010/04/30_256.html
.NET Framework
System.Web.helpers Json System.Web.Extentions.dll JavaScriptSerializer
投稿2015/05/11 11:09
総合スコア66
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/05/12 00:05
2015/05/12 00:29

0
操作ミスです
投稿2015/05/11 10:10
編集2015/05/11 10:11総合スコア87
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
これも誤動作です
投稿2015/05/11 10:08
編集2015/05/11 10:23総合スコア87
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
こんにちは。
一定のルールに従い本処理で取扱いたいのです。
この一定のルールが事前に決まっていれば可能だと思います。
例えば、
list.dic[ListKey].Add( ListKey, "テストです" );
の時に、ABCDそれぞれどのような動きをさせたいですか?
投稿2015/05/11 09:55
総合スコア4791
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/05/11 11:09

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。