Чи є більш елегантний спосіб додавання елемента до словника <> безпечно?


141

Мені потрібно додати пари ключів / об’єктів до словника, але я, звичайно, спершу потрібно перевірити, чи ключ вже існує в іншому випадку, я отримую помилку " ключ уже існує в словнику ". Код нижче вирішує це, але незграбний.

Який більш елегантний спосіб зробити це, не роблячи подібного методу допоміжної струни?

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

Відповіді:


246

Просто використовуйте індексатор - він замінить, якщо він уже є, але він не повинен бути там спочатку:

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

В основному використовувати, Addякщо існування ключа вказує на помилку (так що ви хочете, щоб вона кинула), а індексатор в іншому випадку. (Це трохи схоже на різницю між трансляцією та використанням asдля еталонних перетворень.)

Якщо ви використовуєте C # 3 і у вас є чіткий набір клавіш , ви можете зробити це ще акуратніше:

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

У вашому випадку це не спрацює, оскільки ініціалізатори колекції завжди використовують, Addщо буде запускати другий Customersзапис.


6
Чудово, не усвідомив просте завдання, подбав про додавання / перезапис, приємно.
Едвард Тангуай

49

Що не так з...

dict[key] = view;

Він автоматично додасть ключ, якщо його немає.


3
Я думаю, що варто зауважити, що якщо ви зберігаєте інт, dict[key] += amountвін не спрацює, якщо ключа не існує
Chris S

22

просто

dict[key] = view;

З документації MSDN на Dictionary.Item

Значення, пов'язане із вказаним ключем. Якщо вказаний ключ не знайдений, операція get перекидає KeyNotFoundException, і операція встановлення створює новий елемент із вказаним ключем .

Мій акцент


10

Як завжди, Джон Скіт потрапляє туди зі швидкістю освітлення з правильною відповіддю, але що цікаво, ви також могли написати свій SafeAdd як метод розширення на IDictionary.

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

9

Хоча використання індексатора явно є правильною відповіддю на вашу конкретну проблему, ще однією більш загальною відповіддю на проблему додавання додаткової функціональності до існуючого типу буде визначення способу розширення.

Очевидно, що це не особливо корисний приклад, але слід пам’ятати про наступний раз, коли виявите справжню потребу:

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

2
Я зазначу, що це стосується лише версій C # 3.0 та вище.
Мехрдад Афшарі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.