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

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

ただいまの
回答率

87.94%

多段構造になっているハッシュテーブルの取り扱いについて

解決済

回答 13

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 19K+

score 81

以下のような多段構造をした構造体を定義しました

public class ListModel
{
    public Dictionary<string, string> A = new Dictionary<string, string>();
    public Dictionary<string, string> B = new Dictionary<string, string>();
    public Dictionary<string, Dictionary<string, string>> C =
        new Dictionary<string, Dictionary<string, string>>();
    public Dictionary<string, List<Dictionary<string, string>>> D =
        new Dictionary<string, List<Dictionary<string, string>>>();
ring, object>();
public Dictionary<string, object> dic = new Dictionary<string, object>();    
// コンストラクタ
    public LayoutModel(){
        this.dic = new Dictionary<string, object> {
                    {"A", A},
                    {"B", B},
                    {"C", C},
                    {"D", D}
        };
    }
}

上記の構造体を以下のよう処理で取扱いたいと思っています。
// この返却値指定もおかしいですよね?(
public ListModel Main(){

  ListModel list = new ListModel();
  List<string> KeyList = {"A","B","C","D"};

  foreach( string ListKey in KeyList )
  {
      // エラーが出ます。。。当たり前ですよね。
      list.dic[ListKey].Add( ListKey, "テストです" );
  }

  // ここの返却値の型の指定の仕方もわかりません。(ListModel.dic を返したいです)
  return list;
}

何がやりたいの?という話なのですが、
画一的な構造ではなく、様々な多段構造をもつハッシュテーブルを
一定のルールに従い本処理で取扱いたいのです。
※出現したkeyによってif or switch 等で条件分岐するような泥臭い方法は極力行いたくない

C#(OR 型の制約がある程度厳密な言語で普段開発される方)は、こういったケースの場合
どのような実装方法(型定義も含めて)で、こういった問題をクリアするのでしょうか?

自分は、PHPから入ったので連想配列辺りのこの辺の処理はあまり意識して組んだことがありません。(データ生成後のアクセスのしやすさは考慮しますが、データ生成の時点では特に型・構造は意識しなくてよいので)

技術的な方法でこういった問題を解決する事ももちろん知りたいのですが、
漠然と感じているのは、そもそもの設計思想だと思っています。
そういった部分も含めて言及・ご意見頂けると大変ありがたいです。

一応、上記処理を利用して作るデータのイメージを掲載します。
dic: {
  A: {
    A-DATA: "123"
  }
  B: {
    B-DATA-1: "B TEST"
    B-DATA-2: "B 2 TEST"
  }
  C: {
    C-1-DATA: {
      C-DATA-1: "hogehoge"
    }
  }
  D: {
    A-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}]
    B-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}]
    C-D: [{"A":"a"},{"B":"b"}],[{"A2":"a2"},{"B2":"b2"}]
  }
}

追記:
質問内容に記載したデータをどのようにシリアライズするかどうかはわかっています。
JSONがどうとか、SOAPだXMLだとかの質問をしているわけではないです。
以下の内容がわかれば知りたいです。

・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない

出来るのであれば出来る方法を出来ないのであれば、こういったニーズが発生した場合どういう風に対処するのかが知りたいです。

自分が、コメントに対してJSONで利用すう前提という事を記載してしまったのがいけないのですが
JSONでデータ通信は問題なく出来ていますので、その辺への言及は大丈夫です。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • katzC4ISR

    2015/05/11 18:50

    C#でJSONを使いたいのではないか,と推察いたしますが,いかがでしょうか?

    キャンセル

  • ShintaroIshida

    2015/05/11 18:56

    katzC4ISR 様

    ご推察通り、まさにその通りです!
    仕様変更があった場合、構成情報を構造体や外部XML等で管理して本処理になるべく手をつけたくないので、苦肉の策なのですが。。。

    キャンセル

  • katzC4ISR

    2015/05/11 20:02

    そうでしたか:-)
    ちょうど,数日前に私も同じ状況に遭遇したので,もしやと思ったのです.
    ということであればC#でのJSONの扱いをちょうどまとめたところだったので,情報を紹介いたします.

    キャンセル

回答 13

check解決した方法

+2

投稿からかなり期間が経過してしまいましたが、
様々な方のご意見を受けて自分なりに問題の解決出来たので
簡単にですが実現方法を掲載しておきます。

1.データ構造をクラス化して対応しました
データ構成もですが、主に各々の階層へpushするメソッドを準備しました。

2.データの準備の順番を見直しました
最初、php的な考え方が抜け切れておらず、最初に最上位にあたるハッシュを定義した上で
二段階目の要素へデータを追加し続けるという方法で実装していたのですが、
要素[A・B・C・D]に格納する予定のハッシュを先に構築し、全ての要素を
準備した後に最上位のハッシュへ各生成したハッシュを格納する事で対応しました。

多段階層をもつハッシュを最初に定義した + その階層へのアクセス方法を
カプセル化できていなかったので、想定している動きが実装出来なかったという事でした。

結果的には、もっと効率が良かったりする方法もあるかと思いますが
自分としては、最低限実現したかった方法が実装できたので満足しています。

また、多くの方に様々なご意見を頂きまして色々な部分で勉強になりました。
特に質問投稿初期からご意見を再三に渡り頂きました

Tak1wa 様
katzC4ISR 様
haru666 様

ありがとうございました。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+1

なるほど,アプローチは2つあると思います

1) DBから読み込むデータを受け取るエンティティクラスを定義する.このエンティティをDataContract~等でJSON文字列化する
2) そうではなくて,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 13:07

    回答ありがとうございます。

    >たとえば,{"Key":"Value"} の場合は,JSONObject.Add(”Key”,"Value")
    >{"Key":["Value"]} の場合は,JSONObject.Add(”Key”,JSONArray.Add("Value"))
    >["Key1":{"Key2":Value}] の場合は,JSONArray.Add("Key1", JSONObject.Add(”Key2”,Value)

    やはりそういう方法に行きつくのですね。
    最初にご提示いただいた様な方法で実装していたのですが、
    ソースが冗長になる+仕様変更の度に処理を追加しないといけないという問題に気が付いて実装方針を改めて今回の様な質問に行きつきました。

    そもそもの仕様がとか、JSONがどうとかというご意見も頂いていますが、
    ハッシュテーブル自体は、言語の仕様としてネストして定義出来るのであとはデータをどのように追加していくか?だけだと思っていたのですが、中々思ったような情報に行きつかない現状です。。

    キャンセル

  • 2015/05/12 17:05

    うーん.ちょっと私が,JSONを出してミスリーディング(みなさんを)してしまったのかもしれないですね.話を巻き戻しましょうか.別の回答を立てますね.

    キャンセル

+1

見も蓋もない話ですが、まずはC#の一般的なコーディングルールを学ぶ方が妥当だと思います。

C#ではこのようにDictionaryをネストしないのが普通です。
Jsonに一定のルールを決定することがC#ではクラスの定義に相当します。
Jsonの連想配列は型の宣言こそありませんが、皆さん型自体は無意識ながら決めていると思います。
やれこのデータ型は文字列である、数値である、別のオブジェクトである、ということを分かって使っているはずです。
これを先に宣言するのがC#です。

C#で連想配列を扱うのは、連想配列でなくてはならない場合のみです。
クラス⇔Json の変換にはJson.NETを使用するといいと思います。
まずC#のクラスについて勉強し、その後Json.NETの利用方法を確認してみてください。
Json.NETの利用方法は、C#とJsonの違いを教えてくれると思います。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/12 13:17

    回答ありがとうございます。

    頂いたご意見をよく読んでみたのですが、以下の点が理解出来ません。

    >C#ではこのようにDictionaryをネストしないのが普通です。
    この普通というのはどのようなケースを指されているのでしょうか?
    単純にハッシュテーブルのネストであれば実装方法が存在するので
    言語として対応してないわけではないと思うのですが。。。

    >C#で連想配列を扱うのは、連想配列でなくてはならない場合のみです。
    これは、このような多様な仕様を満たす想定であればそれようのクラスを定義すべき
    という事でしょうか?

    他の内容に関しては、回答を頂いておきながら大変申し訳ありませんが、
    そもそも理解しているので、大丈夫です。(一応、PHP・RubyでJSONを使ったRESTの実装したことありますので。。)

    キャンセル

  • 2015/05/12 14:37

    >> C#ではこのようにDictionaryをネストしないのが普通です。
    > この普通というのはどのようなケースを指されているのでしょうか?
    一般的なC#のコーディングを行う上での話をしているつもりです。
    Dictionary型をネストするぐらいなら通常はクラス自体をネストします。

    > 画一的な構造ではなく、様々な多段構造をもつハッシュテーブルを
    > 一定のルールに従い本処理で取扱いたいのです。
    上記のように書かれていますが、本当にそれらは連想配列の形式を保持しつづける必要があるのでしょうか。
    「様々な多段構造をもつ」というのが様々なクラスの複合体である、というように読めます。
    Jsonの時にきちんとした利用方法があるなら一度クラスに落とし込むことができるはずです。

    Dictionary型を利用するということは型の情報を保持しないと意味するのと殆ど同義です。
    Dictionary型を利用することで以下のデメリットが発生します。
    ・他の開発者が見てどのようにクラスを扱うかが分からない
    ・型情報からどのようなメンバ(Key)が登録されているかわからない
    ・C#の強力な型リフレクション機能が使えない
    ・インテリセンスが使えない
    他にもコンストラクタが使えないとか、Keyが登録されている/いないという3値論理のような問題が組み込まれてしまうとか、デメリットは沢山あります。

    >> C#で連想配列を扱うのは、連想配列でなくてはならない場合のみです。
    > これは、このような多様な仕様を満たす想定であればそれようのクラスを定義すべきという事でしょうか?
    そうです。基本的にはクラスを定義すべきです。

    エンドユーザーが独自に定義できるインタプリタをC#内に実装しているとか、そういう場合でなら連想配列を使います。
    例えば、メールの定型文機能とか、ASP.NETにおけるURLと機能のマッピングであるとかですね。
    こういう場合、Dictionary型のKeyValuePairの扱いも一定になります。
    ある「Key」の場合「Value」はこんな風に扱わなくてはならない、ということがルールとして存在するなら、Dictionary型を使ってはいけません。
    それはクラス化するに足る制約をDictionaryに付加しています。

    もちろん細かく見ていけば例外もあります。
    ただ安易にDictionary型を使う、ということであれば「それはC#らしくない」と言わなければならないでしょう。

    キャンセル

  • 2015/05/13 08:56

    詳細に返答頂きありがとうございました。

    >「様々な多段構造をもつ」というのが様々なクラスの複合体である、というように読めます。
    >Jsonの時にきちんとした利用方法があるなら一度クラスに落とし込むことができるはずです。

    確かにおっしゃられる通りだと思います。
    コメント頂き思ったのが、自分の中でクラスというものは、処理を実装してそれを切り分ける際に(拡張性を持たせる)作成するものという先入観があったと思います。

    よくよく考えてみるとそもそも構造体自体もクラスなわけですから汎用的な位置づけで利用するのであればクラスの利用を検討すべきですね。

    >エンドユーザーが独自に定義できるインタプリタをC#内に実装しているとか、そういう場合でなら連想配列を使います。
    >例えば、メールの定型文機能とか、ASP.NETにおけるURLと機能のマッピングであるとかですね。

    まだちょっと haru666 様が、おっしゃられるハッシュの使いどころはおぼろげですが、
    これはC#を使い倒していくうえで自分自身に覚えこませていこうと思います。
    (今までの言語も全てそうだったので。。。)

    >それはクラス化するに足る制約をDictionaryに付加しています。
    まずはここを念頭において、クラス設計の見直しをやってみようと思います。

    キャンセル

0

こんにちは。

一定のルールに従い本処理で取扱いたいのです。 
この一定のルールが事前に決まっていれば可能だと思います。

例えば、
list.dic[ListKey].Add( ListKey, "テストです" );
の時に、ABCDそれぞれどのような動きをさせたいですか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/11 19:45

    すみません。「katzC4ISRさん」でした…。
    katzC4ISR様、大変失礼致しました。

    キャンセル

  • 2015/05/11 20:02

    もし、単純にJSONを扱いたいという要件なのであれば
    JSONイメージをご提示頂けると助かります。

    キャンセル

  • 2015/05/11 20:09

    いえいえ,お気になさらず.

    キャンセル

0

どうも,改めまして.

C#でJSONを扱うには,幾つか選択肢があります.以下,Webに出回っている情報のポインタになりますが,ご紹介いたします.
おおむね
    http://www2.hatenadiary.jp/entry/2013/12/14/030112
によくまとめられています.

概要をお話いたしますと,
  1.  ちゃんとJSONを扱いたい > Json.NET, DynamicJSON
  2.  ある程度固定の情報の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/12 09:24

    katzC4ISR 様

    まさにその通りです!

    付け加えますと、構造で例に出している A~Dハッシュの単体の構成であれば
    問題なく実装出来ているのですが、dicハッシュにそれらのハッシュテーブルを当て込んだ後、どのように要素を追加していけばよいのか?
    そもそもこういったやり方自体が問題なのか?がわかっていません。

    再三に渡り、わかりづらい質問をご理解頂き端的に解して頂いてありがとうございます。

    キャンセル

  • 2015/05/12 09:29

    なるほど。
    では、クライアント側の仕様に合わせた形式でJSONを組み立てたいのですね?
    であればクライアントの仕様にあわせたエンティティを用意しDataContractJsonSerializerでエンコードしてやっては如何ですか?

    キャンセル

  • 2015/05/12 10:08

    Tak1wa様

    コメントありがとうございます。
    >クライアントの仕様にあわせたエンティティを用意し
    これが質問に投稿したソースです。上記の別回答で katzC4ISR様がおっしゃっている通り、TBLが多種多様な構造なので、それらをビジネスロジック側で整理⇒一本化して、質問に記載している処理で、纏め上げたいというのがやりたいことです。

    分かりづらくて申し訳ないです。

    キャンセル

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 13:27

    回答ありがとうございます。

    >今は ASP.Net MVCで提供されているんじゃないでしょうか。
    ご指摘通り、大枠のプロジェクトはASP.NetのMVCで構築しております。
    XMLが何か?SOAPがどういった通信を行うかは、言語に偏った話ではありませんので、
    理解しているつもりです。

    参考の記事までありがとうございます。
    現状としては、MVCモデルを利用したJSONデータの受け取り(REST)は出来ています。
    質問させて頂いているのは、あくまでも内容に記載しているようなハッシュテーブルの取り扱いに関してです。

    >ただ、他の回答者も指摘されているとおり、サーバ側できちんとモデル定義をすることは必要です。
    確かにそうですね。ただ今回の場合、受け取り側のクライアントが提示した仕様ですので極力手を入れたくありません。プラス、仕様変更に柔軟に対応出来る実装を行いたいのです。実現可能な方法を提案する事も最終的には考えていますが。

    >それは C#だから 型付き言語だからというのではなく、PHPでもそうだったはずですけどね。

    おっしゃられる通りですが、厳密に言うとPHPにもちゃんとデータ型の概念は存在します。ただ、配列や連想配列の取り扱いに関してはかなり直感的に扱えます。(悪く言えば適当に実装しても動く)
    今回の質問は、そういった部分を質問させて頂いております。
    分かりづらい質問で大変申し訳ないです。

    キャンセル

0

・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法 
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない

this.dic = new Dictionary<string, object> {

ここがobject型なので,値を取り出したところでそのままでは構造の違うハッシュには格納してくれませんね.


すみません,元のコードに戻って

list.dic[ListKey].Add( ListKey, "テストです" ); 
の時に、ABCDそれぞれどのような動きをさせたいですか?

ここから再開いたしましょう.たとえば,このAddが成功したとして,
ABCDはどのように変化してほしいですか?

 

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

C#で、各要素に構造の違うハッシュテーブルを詰め込む方法
これ同じ事考えていろいろ試したことがあるのですがデータクラスはobjectで定義しておいて処理を行うメソッドをジェネリックにして使うのが私の限界でした。

objectを型パラメータで指定された型にキャストして、ごにょごにょ処理をすると。
型制約とかで「一定のルール」の範囲を絞ることも出来ると思います。
ただ、型増えるわ共通化しすぎていろんなところで依存しまくるわ(設計が悪いだけかもしれないけど)・・・・これだったらLinqつかっちゃったほうが早いなぁと今は思ってます。。。

最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない
リフレクションで呼んであげれば良いんじゃないかな
ttp://dobon.net/vb/dotnet/programing/typeinvokemember.html

イメージ的にはアンマネージDLLのメソッド使う感じでメンバを呼び出す感じ。
当然使われる側の正確なメソッドの定義を使う側が知っている必要があります。


総じて「どんな構造であるか使う側が知らないでその構造には触れない」ってのが一般論かと。
究極的には上のリフレクションでメンバ名を「文字列」で扱うことが出来るんで、動的に構造を解析して操作することも出来なくはないと思いますが・・・・まぁ業務アプリでそんなの作ったら普通怒られますよね・・・

以上

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/13 09:32

    回答ありがとうございます。

    >データクラスはobjectで定義しておいて処理を行うメソッドを
    >ジェネリックにして使うのが私の限界でした。

    なるほど。そういった実装方法もあるのですね。
    ジェネリックの概念については、回答を頂いてから知りました。

    >ただ、型増えるわ共通化しすぎていろんなところで依存しまくるわ
    >(設計が悪いだけかもしれないけど)・・・・これだったらLinqつかっちゃったほうが早いなぁと今は思ってます。。。

    自分も処理の共通化を念頭において今回のような考えに至ったのですが、依存の弊害も確かに考慮しないといけないですね。

    >リフレクションで呼んであげれば良いんじゃないかな
    一応考えはあったのですが、データ=変数という自分の中の先入観があったのもありまして、なんだかなぁ~と思ってスルーしていました。

    haru666様の回答~コメントを頂いて自分の中の先入観に気づく事が出来たので、リフレクションも検討しようと思います。

    >総じて「どんな構造であるか使う側が知らないでその構造には触れない」ってのが一般論かと。
    確かにその通りだと思います。実際、型制約が緩い言語ですとその辺の弊害が意図しない形で発生する認識はあるので。

    >究極的には上のリフレクションでメンバ名を「文字列」で扱うことが出来るんで、動的に構造を解析して操作することも出来なくはないと思いますが・・・・まぁ業務アプリでそんなの作ったら普通怒られますよね・・・

    ここの普通怒られるという部分がよくわかりませんでした。
    例えば、ビジネスロジック側は基本的に変更しない。
    処理対象となるデータをXMLやDBに準備して、処理対象の管理をするという方法は
    問題になるという事でしょうか?であれば、どういったケースが想定されるのでしょうか?質問とは異なる疑問ですが、お手数でなければ教えて頂けますと幸いです。

    キャンセル

  • 2015/05/13 10:36

    >ここの普通怒られるという部分がよくわかりませんでした。
    >例えば、ビジネスロジック側は基本的に変更しない。
    >処理対象となるデータをXMLやDBに準備して、処理対象の管理をするという方法は
    問題になるという事でしょうか?
    すみません。もっと無制限的な意味で、特に深い意味はないです。
    ご提示頂いた例は仕様に基づく設計なり実装なりだと思うので必要なことだと思います。
    仕様に基づく構造の範囲を逸脱して動的にデータ構造解析してそれを良しとするのは良くないよねぇ・・・という意味でした。
    しかし改めて考えてみると生データからデータオブジェクト起こす解析部分は無制限にしておいて、データ構造が仕様に基づいているか判断部分を別に設ければ良いのかなぁ・・・と思いました;その程度なのであまりおきになさらず;

    キャンセル

  • 2015/05/13 10:49

    追記です。

    データ構造が何でも受け入れられる必要があるのって、異なる構造が同時に使用される場合だと思いますが、その場合はパターン識別による構造管理が必要になります。簡単なアプリだとそれをクラス名やら構造体名やらで識別するわけですが、動的に生成される構造はこれらが使えなくなります=言語的な制約のサポートを受けれなくなります。私自身それを良しとするプロジェクトに参画したことが無いのも理由の一つです。(尚私は経験貧弱です;)

    キャンセル

  • 2015/05/13 13:48

    サンプル作ってみました。

    ↓↓↓↓↓↓

    // 連想リスト
    public class DictionaryEX : Dictionary<string, object>
    {
    public bool GetValue<T>(string key, out T value)
    {
    var result = false;
    try
    {
    value = (T)this[key];
    }
    catch
    {
    // キーが無い場合、キャストできない場合はどうするか考える必要がある
    value = default(T);
    }

    return result;
    }

    public T GetValue<T>(string key)
    {
    return (T)this[key];
    }
    }

    // おまけでリスト
    public class ListEx : List<object>
    {
    public bool GetValue<T>(int index, out T value)
    {
    var result = false;
    try
    {
    // キーが無い場合、キャストできない場合はどうするか考える必要がある
    value = (T)this[index];
    }
    catch
    {
    value = default(T);
    }

    return result;
    }

    public T GetValue<T>(int index)
    {
    return (T)this[index];
    }
    }


    static void Main(string[] args)
    {
    // データを作ってみる
    var val1 = new DictionaryEX();
    var val2 = new DictionaryEX();
    var val3 = new DictionaryEX();
    var val4 = new ListEx();

    var val5 = "Val5";
    var val6 = (short)6;
    var val7 = true;

    val1.Add("Value1", val1);
    val1.Add("Value2", val2);
    val1.Add("Value5", val5);
    val1.Add("Value6", val6);
    val1.Add("Value7", val7);

    val2.Add("Value3", val3);
    val2.Add("Value5", val5);
    val2.Add("Value6", val6);
    val2.Add("Value7", val7);

    val3.Add("Value4", val4);

    val4.Add(val5);
    val4.Add(val6);

    // 上の処理で出来上がるデータをXML風に表現
    // <Value1>
    // <Value1>
    // 無限ループなので省略
    // </Value1>
    // <Value2>
    // <Value3>
    // <Value4>
    // <Value4Item>Val5</Value4Item>
    // <Value4Item>6</Value4Item>
    // </Value4>
    // </Value3>
    // <Value5>Val5</Value5>
    // <Value6>6</Value6>
    // <Value7>true</Value7>
    // </Value2>
    // <Value5>Val5</Value5>
    // <Value6>6</Value6>
    // <Value7>true</Value7>
    // </Value1>

    // 実際にアクセスしてみる
    Method(val1);

    }

    static private void Method(DictionaryEX collection)
    {
    var val1 = default(DictionaryEX);
    var val2 = default(ListEx);

    var val5 = default(string);
    var val6 = default(short);
    var val7 = default(bool);

    collection.GetValue("Value1", out val1);
    collection.GetValue("Value2", out val1);
    collection.GetValue("Value3", out val1); // 内部でランタイムエラー(キー無し)
    collection.GetValue("Value5", out val1); // 内部でランタイムエラー(キャスト不可)
    collection.GetValue("Value7", out val7);

    // 一歩ずつ。戻り値チェックして堅実に(チェック省略)
    collection.GetValue("Value2", out val1);
    val1.GetValue("Value3", out val1);
    val1.GetValue("Value4", out val2);
    val2.GetValue(0, out val5);
    val2.GetValue(1, out val6);

    // 直列で一気に。例外なんて怖くない。
    val5 = collection.GetValue<DictionaryEX>("Value2")
    .GetValue<DictionaryEX>("Value3")
    .GetValue<ListEx>("Value4")
    .GetValue<string>(0);
    }

    ↑↑↑↑↑↑

    チャレンジしたころの記憶を掘り起こしてサンプル作ってみました。
    まぁ要するにキャストしてるだけですが・・・・

    キャンセル

0

一つのDictionaryにValueやネストしたDictionaryを入れ、複雑な構造を作りたいということですか?
その場合、最も適切な方法は、Dictionary<string, dynamic>でDictionaryを宣言し、各要素の追加を行います。
ネストさせるDictionaryも全て<string, dynamic>で作成する必要があります。
インテリセンスが効かなくなる問題はありますが、ネストしたDictionaryに値を追加するときもAddを使うだけで済みます。
動的な構造変更をしていることになるので、型が一致しているかどうかを管理するのはプログラマの責任となります。

var dict = new Dictionary<string, dynamic>();
dict.Add("A", new Dictionary<string, dynamic>());
dict.Add("B", new Dictionary<string, dynamic>());
dict.Add("C", new Dictionary<string, dynamic>());

dict["A"].Add("1", "ABCDE");
dict["A"].Add("2", "FGHIJ");
dict["B"].Add("x", "test");

dict["C"].Add("AAA", new Dictionary<string, dynamic>());
dict["C"]["AAA"].Add("1", "hogehoge");

var value = dict["A"]["1"]; // -> value = "ABCDE"

静的な型付けを持つC#で構造の違うオブジェクトを同様に扱いたい場合はobjectかdynamicを使うか、ジェネリックな入れ物を作成する方法で対応できます。この用途で使える入れ物の作成方法はここには書きませんが、結局は型消去をするので値の取り出しにキャストが必要になり、あまり有用ではありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

これも誤動作です

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

操作ミスです

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

うーむ、難しい話になってきましたね。

・C#で、各要素に構造の違うハッシュテーブルを詰め込む方法 
・最上位 VALUEにobjectで引き渡す事は出来るが引き渡した後に各要素への値追加の方法がわからない 

まずJSONのことはキッパリ忘れますね。
上記をやりたいだけであれば、
Dictionary<string, IDictionary>にしてやれば詰め込めます。

ただし再帰的にDictionaryまたはValueとして扱いたいのでしょうから、
以下のようにDictionary自体を作成して、object型の部分をカスタムクラス内で吸収してやれば実装自体は出来る気がしてます。

public class DictionaryEx : Dictionary<string, object>, IDictionary<string, DictionaryEx>, IDictionary<string, string>
↑頓珍漢なこと言ってました。試してみましたがダメっぽかったです。


ここからJSONを前提とした話にちょっと戻ります(お気に障ったらすみません)
質問内容に記載したデータをどのようにシリアライズするかどうかはわかっています。 
私が勘違いしていたら申し訳ないのですが、皆さんが仰っているのでは逆の話で、
クライアントから受け取ったJSON文字列を、ASP.NET側でフレームワークを用いてデシリアライズしてやれば、
Dictionary型をネストするぐらいなら通常はクラス自体をネストします。
とするだけで簡単に出来るしスマートだし変更にも強いよ、と言っているのだと思います。

質問文の最初に
foreach( string ListKey in KeyList )
とありましたが、ひょっとしてループでぐるぐるとJSON⇔POCOの変換をかけようとしていませんか?

↑ これも私の検討違いかも…。質問者さんはデシリアライズのことについては触れてませんでしたね。

本回答は無視してください。失礼しました。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

-1

エラーが出るのは宣言された型と入力されるデータに互換性がないからです。
試しに「テストです」の部分を null に変えたらうまくいくのではないですか?

AおよびBのデータ型は文字列なので、文字列である「テストです」は代入できます。
CおよびDのデータ型はDictionary<string, string>なので、文字列は代入できません。

多段構造とかハッシュテーブルとか言う以前の問題だと思います。
なんでも代入できる変数が欲しければ、object あるいは dynamic を使うべきでしょう。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2015/05/18 15:29

    なぜか-1されていますが、背伸びしすぎて問題の分離ができていないように見受けられます。
    A は Dictionary<string, string> なので、string をキーとして string のデータを代入できます。
    C は Dictionary<string, Dictionary<string, string>> なので、string をキーとして Dictionary<string, string> のデータを代入できます。
    あなたの質問ではこのどちらにも string のデータを代入しようとしています。
    これがエラーの原因です。
    ここを理解してから多段構造を勉強するのが近道だと思います。

    キャンセル

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

  • ただいまの回答率 87.94%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る