Gibt es eine elegantere Möglichkeit, ein Element sicher zu einem Wörterbuch <> hinzuzufügen?

141

Ich muss einem Wörterbuch Schlüssel / Objekt-Paare hinzufügen, aber ich muss natürlich zuerst prüfen, ob der Schlüssel bereits vorhanden ist, andernfalls wird der Fehler " Schlüssel ist bereits im Wörterbuch vorhanden " angezeigt. Der folgende Code löst dies, ist aber klobig.

Was ist eleganter, um dies zu tun, ohne eine solche String-Helfer-Methode zu entwickeln?

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;
            }
        }
    }
}
Edward Tanguay
quelle

Antworten:

246

Verwenden Sie einfach den Indexer - es wird überschreiben , wenn es schon da ist, aber es nicht haben , dort zu sein zuerst:

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

Grundsätzlich verwenden, Addwenn das Vorhandensein des Schlüssels auf einen Fehler hinweist (Sie möchten also, dass er ausgelöst wird) und den Indexer anderweitig. (Es ist ein bisschen wie der Unterschied zwischen Casting und Verwendung asfür Referenzkonvertierungen.)

Wenn Sie C # 3 verwenden und einen bestimmten Schlüsselsatz haben , können Sie dies noch übersichtlicher gestalten:

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

Dies funktioniert in Ihrem Fall jedoch nicht, da Sammlungsinitialisierer immer Addden zweiten CustomersEintrag verwenden.

Jon Skeet
quelle
6
Ausgezeichnet, nicht realisiert, dass eine einfache Zuordnung das Problem des Hinzufügens / Überschreibens gelöst hat, nett.
Edward Tanguay
49

Was ist falsch mit...

dict[key] = view;

Der Schlüssel wird automatisch hinzugefügt, wenn er nicht vorhanden ist.

Mehrdad Afshari
quelle
3
Eine Sache, die ich denke, ist erwähnenswert, dass, wenn Sie ein int speichern, dict[key] += amountnicht funktioniert, wenn der Schlüssel nicht existiert
Chris S
22

einfach

dict[key] = view;

Aus der MSDN-Dokumentation von Dictionary.Item

Der dem angegebenen Schlüssel zugeordnete Wert. Wenn der angegebene Schlüssel nicht gefunden wird, löst eine get-Operation eine KeyNotFoundException aus, und eine festgelegte Operation erstellt ein neues Element mit dem angegebenen Schlüssel .

Mein Schwerpunkt

Steve Gilham
quelle
10

Wie üblich steigt John Skeet mit Lichtgeschwindigkeit und der richtigen Antwort ein, aber interessanterweise hätten Sie Ihre SafeAdd auch als Erweiterungsmethode in IDictionary schreiben können.

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

Obwohl die Verwendung des Indexers eindeutig die richtige Antwort für Ihr spezifisches Problem ist, besteht eine weitere allgemeinere Antwort auf das Problem, einem vorhandenen Typ zusätzliche Funktionen hinzuzufügen, darin, eine Erweiterungsmethode zu definieren.

Offensichtlich ist dies kein besonders nützliches Beispiel, aber etwas, das Sie beachten sollten, wenn Sie das nächste Mal einen echten Bedarf finden:

public static class DictionaryExtensions
{
    public static void SafeAdd<TKey, TValue>(this Dictionary<TKey, TValue> dict, 
                                             TKey key, TValue value)
    {
        dict[key] = value;
    }
}
Daniel Earwicker
quelle
2
Ich würde erwähnen, dass dies nur für C # 3.0 und höher gilt.
Mehrdad Afshari