Comment cette initialisation du dictionnaire C # est-elle correcte?

64

Je suis tombé sur ce qui suit et je me demande pourquoi cela n'a pas soulevé d'erreur de syntaxe.

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

Notez que le "," manque entre "MyA" et "OtherAs".

C'est là que la confusion se produit:

  1. Le code se compile.
  2. Le dictionnaire final "dict" ne contient que trois éléments: "Id", "Tribes" et "MyA".
  3. La valeur pour tous sauf "MyA" est correcte,
  4. "MyA" prend la valeur déclarée pour "OtherAs", tandis que sa valeur d'origine est ignorée.

Pourquoi n'est-ce pas illégal? Est-ce par conception?

Dantte
la source
1
@Steve, c'est ce qu'il demande. J'ai collé cela dans sharplab et il semble qu'au départ, il OtherAssoit ajouté comme clé dans ce que serait le MyAdictionnaire. (Nom = Solo, Points = 88 plus OtherAs = List <Dictionnaire <chaîne, objet >>) sauf qu'il ne l'affecte jamais . Au lieu de cela, il place la liste des pronostics, ne contenant désormais que la seule entrée Points = 1999 dans l' MyAemplacement remplaçant ce que l'on pourrait penser y appartenir.
pinkfloydx33
1
Le lien était trop long pour coller dans le premier commentaire. C'est vraiment étrange. sharplab.io/…
pinkfloydx33
1
Oui, je l'ai testé avec LinqPad et j'ai obtenu le même résultat. Je ne sais pas ce qui se passe ici. Voyons voir si un gourou de C # pourrait faire la lumière ici.
Steve
1
Si vous changez le premier dictionnaire en <string, string> and modify Points to "88" `vous obtenez alors une erreur de compilation" Impossible de convertir implicitement le type 'System.Collections.Generic.List <System.Collections.Generic.Dictionary <chaîne, objet >>' en 'chaîne' " ce qui m'a aidé à trouver la réponse!
pinkfloydx33
2
@OlegI Je ne pense pas que ce soit un bug du compilateur. Beaucoup de bonnes explications déjà fournies dans les réponses. Mais si vous essayez var test = new Dictionary<string, object> { ["Name"] = "Solo", ["Points"] = 88 }["OtherAs"] = new List<Dictionary<string, object>> { new Dictionary<string, object> { ["Points"] = 1999 } };, expliquez-le plus en détail.
MKR

Réponses:

54

La virgule manquante fait toute la différence. Il provoque l'application de l'indexeur ["OtherAs"]sur ce dictionnaire:

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

Vous dites donc essentiellement:

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

Notez qu'il s'agit d'une expression d'affectation ( x = y). Voici le xdictionnaire avec "Nom" et "Points", indexé avec "OtherAs"et yest le List<Dictionary<string, object>>. Une expression d'affectation évalue la valeur affectée ( y), qui est la liste des dictionnaires.

Le résultat de toute cette expression est ensuite affecté à la clé "MyA", c'est pourquoi "MyA" a la liste des dictionnaires.

Vous pouvez confirmer que c'est ce qui se passe en modifiant le type du dictionnaire 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
    }
}

Voici votre code, mais reformaté et quelques parenthèses ajoutées pour illustrer comment le compilateur l'a analysé:

["MyA"] 
= 
(
    (
        new Dictionary<string, object>
        {
            ["Name"] = "Solo",
            ["Points"] = 88
        }["OtherAs"] 
    )
    = 
    (
        new List<Dictionary<string, object>>
        {
            new Dictionary<string, object>
            {
                ["Points"] = 1999
            }
        }
    )
)
Balayeuse
la source
1
Il changeait le type de valeur de dictionnaire de objectà stringcela m'a donné un message d'erreur semblable et le aha moment qui a déclenché la réponse. On dirait que vous m'avez battu - je reproche de taper la réponse sur mon téléphone
:-p
19

Ce qui se passe ici, c'est que vous créez un dictionnaire puis l'indexez. Le résultat de l'indexation / expression d'affectation est ensuite renvoyé et c'est ce qui est affecté dans l' MyAemplacement du dictionnaire.

Cette:

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

Peut être divisé en code pseudo suivant:

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

Le résultat de l'affectation à l'indexeur du deuxième dictionnaire est renvoyé (l'affectation renvoie la valeur affectée / côté droit). Ce dictionnaire est un local temporaire qui "disparaît dans l'éther". Le résultat de l'indexeur (la liste des dictionnaires) est ce qui est finalement placé dans le dictionnaire principal.

Il s'agit d'un cas étrange, qui est plus facile à tomber en raison de l'utilisation de objectcomme type de valeurs de dictionnaire.

pinkfloydx33
la source