web-dev-qa-db-fra.com

Existe-t-il un moyen plus élégant d’ajouter un élément à un dictionnaire <> en toute sécurité?

J'ai besoin d'ajouter des paires clé/objet à un dictionnaire, mais je dois bien sûr d'abord vérifier si la clé existe déjà, sinon l'erreur "la clé existe déjà dans le dictionnaire". Le code ci-dessous résout ce problème mais est maladroit.

Quel est un moyen plus élégant de faire cela sans créer une méthode d’aide à la chaîne comme celle-ci?

using System;
using System.Collections.Generic;

namespace TestDictStringObject
{
    class Program
    {
        static void Main(string[] args)
        {
            Dictionary<string, object> currentViews = new Dictionary<string, object>();

            StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view1");
            StringHelpers.SafeDictionaryAdd(currentViews, "Customers", "view2");
            StringHelpers.SafeDictionaryAdd(currentViews, "Employees", "view1");
            StringHelpers.SafeDictionaryAdd(currentViews, "Reports", "view1");

            foreach (KeyValuePair<string, object> pair in currentViews)
            {
                Console.WriteLine("{0} {1}", pair.Key, pair.Value);
            }
            Console.ReadLine();
        }
    }

    public static class StringHelpers
    {
        public static void SafeDictionaryAdd(Dictionary<string, object> dict, string key, object view)
        {
            if (!dict.ContainsKey(key))
            {
                dict.Add(key, view);
            }
            else
            {
                dict[key] = view;
            }
        }
    }
}
124
Edward Tanguay

Utilisez simplement l'indexeur - il écrasera s'il est déjà là, mais il n'a pas have être le premier:

Dictionary<string, object> currentViews = new Dictionary<string, object>();
currentViews["Customers"] = "view1";
currentViews["Customers"] = "view2";
currentViews["Employees"] = "view1";
currentViews["Reports"] = "view1";

Fondamentalement, utilisez Add si l'existence de la clé indique un bogue (vous voulez donc le lancer) et l'indexeur sinon. (C'est un peu comme la différence entre le casting et l'utilisation de as pour les conversions de référence.)

Si vous utilisez C # 3 et que vous avez un jeu de clés distinct, vous pouvez rendre ceci encore plus net:

var currentViews = new Dictionary<string, object>()
{
    { "Customers", "view2" },
    { "Employees", "view1" },
    { "Reports", "view1" },
};

Cela ne fonctionnera pas dans votre cas cependant, car les initialiseurs de collection utilisent toujours Add, ce qui jettera la deuxième entrée Customers.

226
Jon Skeet

Quel est le problème avec...

dict[key] = view;

Cela ajoutera automatiquement la clé si elle n'existe pas.

44
Mehrdad Afshari

simplement

dict[key] = view;

De la documentation MSDN de Dictionary.Item

La valeur associée à la clé spécifiée. Si la clé spécifiée n'est pas trouvée, une opération get lève une exception KeyNotFoundException et une opération l'opération set crée un nouvel élément avec la clé spécifiée.

Mon emphase

20
Steve Gilham

Comme d'habitude, John Skeet arrive là-bas à la vitesse de l'éclairage avec la bonne réponse, mais il est intéressant de noter que vous auriez aussi pu écrire votre SafeAdd comme méthode d'extension dans IDictionary.

public static void SafeAdd(this IDictionary<K, T>. dict, K key, T value)...
10
rohancragg

Bien que l'utilisation de l'indexeur soit clairement la bonne réponse à votre problème spécifique, une autre solution plus générale au problème de l'ajout de fonctionnalités supplémentaires à un type existant serait de définir une méthode d'extension.

Il est évident que ce n’est pas un exemple particulièrement utile, mais qu’il faut garder à l’esprit pour la prochaine fois que vous constaterez un besoin réel:

public static class DictionaryExtensions
{
    public static void SafeAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, 
                                             TKey key, TValue value)
    {
        dict[key] = value;
    }
}
7
Daniel Earwicker