Esiste un modo più elegante di aggiungere un elemento a un dizionario <> in modo sicuro?


141

Devo aggiungere coppie chiave / oggetto a un dizionario, ma ovviamente devo prima verificare se la chiave esiste già, altrimenti viene visualizzato l' errore " chiave già esistente nel dizionario ". Il codice seguente risolve questo problema ma è goffo.

Qual è un modo più elegante di farlo senza creare un metodo di supporto stringa come questo?

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

Risposte:


246

Basta usare l'indicizzatore: sovrascriverà se è già lì, ma non deve essere lì prima:

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

Fondamentalmente usa Addse l'esistenza della chiave indica un bug (quindi vuoi che venga lanciato) e l'indicizzatore altrimenti. (È un po 'come la differenza tra casting e utilizzo asper conversioni di riferimento.)

Se stai usando C # 3 e hai un set distinto di chiavi , puoi rendere questo ancora più ordinato:

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

Ciò non funzionerà nel tuo caso, poiché gli inizializzatori di raccolta usano sempre ciò Addche verrà inserito nella seconda Customersvoce.


6
Eccellente, non ho realizzato che un semplice compito si è occupato del problema di aggiunta / sovrascrittura, bello.
Edward Tanguay,

49

Cosa c'è che non va in ...

dict[key] = view;

Aggiungerà automaticamente la chiave se è inesistente.


3
Una cosa che penso valga la pena notare che se stai memorizzando un int, dict[key] += amountnon funzionerà se la chiave non esiste
Chris S

22

semplicemente

dict[key] = view;

Dalla documentazione MSDN di Dictionary.Item

Il valore associato alla chiave specificata. Se la chiave specificata non viene trovata, un'operazione get genera KeyNotFoundException e un'operazione set crea un nuovo elemento con la chiave specificata .

La mia enfasi


10

Come al solito John Skeet entra lì con velocità di illuminazione con la risposta giusta, ma è interessante notare che potresti anche aver scritto SafeAdd come metodo di estensione su IDictionary.

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

9

Sebbene l'utilizzo dell'indicizzatore sia chiaramente la risposta giusta per il tuo problema specifico, un'altra risposta più generale al problema dell'aggiunta di funzionalità aggiuntive a un tipo esistente sarebbe quella di definire un metodo di estensione.

Ovviamente questo non è un esempio particolarmente utile, ma qualcosa da tenere a mente per la prossima volta che trovi un reale bisogno:

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

2
Vorrei menzionare che questo è applicabile solo a C # 3.0 e versioni successive.
Mehrdad Afshari,
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.