Come è corretta questa inizializzazione del dizionario C #?


64

Mi sono imbattuto in quanto segue e mi chiedo perché non abbia generato un errore di sintassi.

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
        }
    }
};

Si noti che "," manca tra "MyA" e "OtherAs".

Questo è dove si verifica la confusione:

  1. Il codice viene compilato.
  2. Il dizionario finale "dict" contiene solo tre elementi: "Id", "Tribes" e "MyA".
  3. Il valore per tutti tranne "MyA" è corretto,
  4. "MyA" accetta il valore dichiarato per "OtherAs", mentre il suo valore originale viene ignorato.

Perché questo non è illegale? Questo è di progettazione?


1
@Steve è quello che sta chiedendo. L'ho incollato in sharplab e sembra che inizialmente OtherAsvenga aggiunto come chiave in quello che sarebbe il MyAdizionario. (Nome = Solo, Punti = 88 più OtherAs = Elenco <Dizionario <stringa, oggetto >>) tranne che non lo assegna mai . Invece inserisce la lista dei dicts, che ora contiene solo la singola voce Points = 1999 nello MyAslot sovrascrivendo ciò che si potrebbe pensare appartenga lì.
pinkfloydx33,

1
Il collegamento era troppo lungo per essere incollato nel primo commento. Questo è davvero strano. sharplab.io/…
pinkfloydx33

1
Sì, l'ho provato con LinqPad e ho ottenuto lo stesso risultato. Non sono sicuro di cosa stia succedendo qui. Vediamo se qualche guru di C # potrebbe far luce qui.
Steve

1
Se si modifica il primo dizionario in <string, string> and modify Points to "88" `viene visualizzato un errore del compilatore" Impossibile convertire in modo implicito il tipo 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <stringa, oggetto >>' in 'stringa' " che in realtà mi ha aiutato a capire la risposta!
pinkfloydx33,

2
@OlegI Non credo sia un bug del compilatore. Molte buone spiegazioni già fornite nelle risposte. Ma se ci provi var test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };lo spiegherai ulteriormente.
MKR

Risposte:


54

La virgola mancante fa la differenza. Fa sì che l'indicizzatore ["OtherAs"]venga applicato su questo dizionario:

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

Quindi essenzialmente stai dicendo:

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

Si noti che questa è un'espressione di assegnazione ( x = y). Ecco il xdizionario con "Nome" e "Punti", indicizzato con "OtherAs"ed yè il List<Dictionary<string, object>>. Un'espressione di assegnazione restituisce il valore assegnato ( y), che è l'elenco dei dizionari.

Il risultato di questa intera espressione viene quindi assegnato alla chiave "MyA", motivo per cui "MyA" ha l'elenco dei dizionari.

Puoi confermare che è ciò che sta accadendo cambiando il tipo di dizionario 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
    }
}

Ecco il tuo codice, ma riformattato e alcune parentesi aggiunte per illustrare come il compilatore lo ha analizzato:

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

1
Stava cambiando il tipo di valore del dizionario da objecta stringquello che mi ha dato un messaggio di errore simile e il momento aha che ha scatenato la risposta. Sembra che tu mi abbia battuto per questo - ho la colpa digitando la risposta sul mio telefono :-p
pinkfloydx33

19

Quello che sta succedendo qui è che stai creando un dizionario e quindi indicizzandolo. Viene quindi restituito il risultato dell'espressione dell'indicizzatore / assegnazione e questo è ciò che viene assegnato nello MyAslot del dizionario.

Questo:

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

Può essere suddiviso nel seguente codice psuedo:

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

Viene restituito il risultato dell'assegnazione all'indicizzatore del secondo dizionario (l'assegnazione restituisce il valore assegnato / lato destro) Quel dizionario è un locale temporaneo che "scompare nell'etere". Il risultato dell'indicizzatore (l'elenco dei dizionari) è ciò che viene inserito nel dizionario principale alla fine.

Questo è un caso strano, che è reso più facile cadere a causa dell'uso di objectcome tipo dei valori del dizionario.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.