このC#辞書の初期化はどのように正しいのですか?


64

私は以下に遭遇しましたが、なぜ構文エラーが発生しなかったのかと思います。

var dict = new Dictionary<string, object>
{
    ["Id"] = Guid.NewGuid(),
    ["Tribes"] = new List<int> { 4, 5 },
    ["MyA"] = new Dictionary<string, object>
    {
        ["Name"] = "Solo",
        ["Points"] = 88
    }
    ["OtherAs"] = new List<Dictionary<string, object>>
    {
        new Dictionary<string, object>
        {
            ["Points"] = 1999
        }
    }
};

「MyA」と「OtherAs」の間に「、」がないことに注意してください。

ここで混乱が起こります:

  1. コードがコンパイルされます。
  2. 最後の辞書「dict」には、「Id」、「Tribes」、「MyA」の3つの要素しか含まれていません。
  3. 「MyA」を除くすべての値が正しいです。
  4. 「MyA」は「OtherAs」の宣言された値を取りますが、元の値は無視されます。

なぜこれは違法ではないのですか?これは仕様ですか?


1
@スティーブは彼が尋ねていることです。私はsharplabにこれを貼り付け、それが当初のように見えるOtherAsものにキーとして追加されるだろうMyA辞書。(Name = Solo、Points = 88 plus OtherAs = List <Dictionary <string、object >>)ただし、割り当てられることはありません。代わりに、dictsのリストを配置し、単一のPoints = 1999エントリのみをMyAスロットに含め、そこに属すると思われるものをオーバーライドします。
pinkfloydx33

1
リンクが長すぎて、最初のコメントに貼り付けることができません。これは確かに奇妙です。sharplab.io/...
pinkfloydx33

1
はい、LinqPadでテストしましたが、同じ結果が得られました。ここで何が起こっているのかわからない。ここで、C#の第一人者が光を当てることができるかどうか見てみましょう。
スティーブ

1
最初の辞書を<string, string> and modify Points to 「88」に変更すると、コンパイラエラー「型 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <string、object >>'を暗黙的に 'string'に変換できません」が表示されます。実際に答えを見つけるのに役立ちました!
pinkfloydx33

2
@OlegIコンパイラのバグだとは思わない。回答ですでに提供されている多くの良い説明。しかし、あなたがしようvar test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };とすると、それをさらに説明します。
MKR

回答:


54

コンマがないことですべての違いが生まれます。これにより、インデクサー["OtherAs"]がこの辞書に適用されます。

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}

だから本質的にあなたは言っています:

new Dictionary<string, object>
{
    ["Name"] = "Solo",
    ["Points"] = 88
}["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
};

これは代入式(x = y)であることに注意してください。ここxでインデックス、「名前」と「ポイント」と辞書である"OtherAs"yされますList<Dictionary<string, object>>。割り当て式yは、割り当てられている値()に評価されます。これは、辞書のリストです。

次に、この式全体の結果がキー「MyA」に割り当てられます。そのため、「MyA」には辞書のリストがあります。

辞書のタイプを変更することで、これが起こっていることを確認できますx

new Dictionary<int, object>
{
    [1] = "Solo",
    [2] = 88
}
// compiler error saying "can't convert string to int"
// so indeed this indexer is applied to the previous dictionary
["OtherAs"] = new List<Dictionary<string, object>>
{
    new Dictionary<string, object>
    {
        ["Points"] = 1999
    }
}

これがあなたのコードですが、再フォーマットし、いくつかの括弧を追加して、コンパイラーがコードを解析した方法を示します。

["MyA"] 
= 
(
    (
        new Dictionary<string, object>
        {
            ["Name"] = "Solo",
            ["Points"] = 88
        }["OtherAs"] 
    )
    = 
    (
        new List<Dictionary<string, object>>
        {
            new Dictionary<string, object>
            {
                ["Points"] = 1999
            }
        }
    )
)

1
それから、辞書の値の型を変更されたobjectstring私のようなエラーメッセージが表示され、与えたのAHA答えを引き起こした瞬間を。あなたは私にそれを打ち負かしたようです-私は私の電話に答えを入力したことを責めます:-p
pinkfloydx33

19

ここで何が起こっているかというと、辞書を作成してから、それに索引を付けているということです。次に、インデクサー/割り当て式の結果が返され、それがMyA辞書スロットに割り当てられます。

この:

["MyA"] = new Dictionary<string, string> 
{
   ["Name"] = "Solo",
   ["Points"] = "88" 
}
["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
       ["Points"] = 1999
   }
}

次の擬似コードに分割できます。

var temp = new Dictionary<string, object>
{ 
   ["Name"] = "Solo", 
   ["Points"] = 88 
};
// indexed contains result of assignment
var indexed = temp["OtherAs"] = new List<Dictionary<string, object>>
{
   new Dictionary<string, object>
   {
      ["Points"] = 1999
   }
};
// value is set to result of assignment from previous step
["MyA"] = indexed;
// temp is discarded

2番目のディクショナリのインデクサーへの割り当ての結果が返されます(割り当ては、割り当てられた値/右側を返します)。そのディクショナリは、単に「エーテルに消える」一時的なローカルです。インデクサー(辞書のリスト)の結果は、最終的にメイン辞書に配置されるものです。

これは奇妙なケースでありobject、辞書値のタイプとしてを使用しているため、簡単に陥ります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.