Различные способы добавления в словарь


какая разница в Dictionary.add(key, value) и Dictionary[key] = value?

Я заметил, что последняя версия не бросает ArgumentException при вставке дубликата ключа, но есть ли причина предпочесть первую версию?

Edit: кто-нибудь авторитетный источник информации об этом? Я пробовал MSDN, но это, как всегда, дикая погоня за гусем: (

7 73

7 ответов:

производительность почти на 100% идентичны. Вы можете проверить это, открыв класс в Reflector.net

Это этот индексатор:

public TValue this[TKey key]
{
    get
    {
        int index = this.FindEntry(key);
        if (index >= 0)
        {
            return this.entries[index].value;
        }
        ThrowHelper.ThrowKeyNotFoundException();
        return default(TValue);
    }
    set
    {
        this.Insert(key, value, false);
    }
}

и это метод Add:

public void Add(TKey key, TValue value)
{
    this.Insert(key, value, true);
}

Я не буду публиковать весь метод Insert, поскольку он довольно длинный, однако объявление метода таково:

private void Insert(TKey key, TValue value, bool add)

и далее вниз в функции, это происходит:

if ((this.entries[i].hashCode == num) && this.comparer.Equals(this.entries[i].key, key))
{
    if (add)
    {
        ThrowHelper.ThrowArgumentException(ExceptionResource.Argument_AddingDuplicate);
    }

, который проверяет, если ключ уже существует, и если это произойдет и параметр add имеет значение true, он выдает исключение.

таким образом, для всех целей и намерений производительность одинакова.

как и несколько других упоминаний, все дело в том, нужна ли вам проверка, для попыток добавления одного и того же ключа дважды.

извините за длинный пост, я надеюсь, что все в порядке.

первая версия добавит новую KeyValuePair в словарь, бросая, если ключ уже находится в словаре. Второй, используя индексатор, добавит новую пару, если ключ не существует, но перезапишет значение ключа, если оно уже существует в словаре.

IDictionary<string, string> strings = new Dictionary<string, string>();

strings["foo"] = "bar";          //strings["foo"] == "bar"
strings["foo"] = string.Empty;   //strings["foo"] == string.empty
strings.Add("foo", "bar");       //throws     

Dictionary.Add(key, value) и Dictionary[key] = value разные цели:

  • использовать Add метод добавить новая пара ключ / значение, существующие ключи не будут заменены (an ArgumentException выбрасывается).
  • используйте индексатор, если вам все равно, существует ли ключ уже в словаре, другими словами: добавьте пару ключ/значение, если ключ не находится в словаре, или замените значение для указанного ключа, если ключ уже находится в словаре.

чтобы ответить на этот вопрос, сначала нам нужно взглянуть на цель словаря и лежащую в его основе технологию.

Dictionary список KeyValuePair<Tkey, Tvalue> где каждое значение представлено своим уникальным ключом. Допустим, у нас есть список ваших любимых продуктов. Каждое значение (название еды) представлено своим уникальным ключом (позиция = насколько вам нравится эта еда).

пример кода:

Dictionary<int, string> myDietFavorites = new Dictionary<int, string>()
{
    { 1, "Burger"},
    { 2, "Fries"},
    { 3, "Donuts"}
};

допустим, вы хотите оставаться здоровым, вы передумали и вы хотите заменить свой любимый "бургер" салатом. Ваш список по-прежнему является списком избранных, вы не будете изменять характер списка. Ваш любимый останется номером один в списке, только его значение изменится. Это когда вы называете это:

/*your key stays 1, you only replace the value assigned to this key
  you alter existing record in your dictionary*/
myDietFavorites[1] = "Salad";

но не забывайте, что вы программист, и с этого момента вы заканчиваете свои предложения ; вы отказываетесь использовать emojis, потому что они будут бросать ошибку компиляции, и весь список избранных основан на индексе 0.

ваш диета тоже изменилась! Поэтому вы снова изменяете свой список:

/*you don't want to replace Salad, you want to add this new fancy 0
  position to your list. It wasn't there before so you can either define it*/
myDietFavorites[0] = "Pizza";

/*or Add it*/
myDietFavorites.Add(0, "Pizza");

есть две возможности с определением, вы либо хотите дать новое определение для чего-то не существующего раньше, либо вы хотите изменить определение, которое уже существует.

добавить метод позволяет добавить запись, но только при одном условии: ключ для этого определения может не существовать в вашем словаре.

теперь мы будем смотреть под капотом. Когда вы делаете словарь ваш компилятор сделайте резервацию для ведра (пробелы в памяти для хранения записей). Ведро не хранит ключи так, как вы их определяете. Каждый ключ хэшируется перед переходом к ведру (определенному Microsoft), стоит упомянуть, что часть значения остается неизменной.

Я буду использовать алгоритм хеширования CRC32 для упрощения моего примера. Когда вы определяете:

myDietFavorites[0] = "Pizza";

что идет в ведро это db2dc565 "пицца" (упрощенный).

при изменении значения в с:

myDietFavorites[0] = "Spaghetti";

вы хэш ваш 0, который снова db2dc565 затем вы смотрите это значение в вашем ведре, чтобы найти, если он там. Если он есть, вы просто переписываете значение, присвоенное ключу. Если его там нет, вы поместите свою ценность в ведро.

при вызове функции Add в вашем словаре, например:

myDietFavorite.Add(0, "Chocolate");

вы хешируете свой 0, чтобы сравнить его значение с теми, что в ведре. Вы можете поместить его в ведро только если это не там.

очень важно знать, как это работает, особенно если вы работаете со словарями типа string или char ключа. Это чувствительно к регистру из-за прохождения хэширования. Так, например, "имя" != "Имя." Давайте использовать наш CRC32, чтобы изобразить это.

значение "имя": e04112b1 Значение параметра "Name": 1107fb5b

Да, это разница, метод Add вызывает исключение, если ключ уже существует.

причина использования метода Add именно в этом. Если словарь не должен содержать ключ уже, вы обычно хотите исключение, чтобы вы знали о проблеме.

учитывая наиболее вероятные сходства в производительности, используйте все, что кажется более правильным и читаемым для части кода, который вы используете.

Я чувствую, что операция, которая описывает добавление, будучи наличие ключа уже действительно редкое исключение лучше всего представлены с add. Семантически это имеет больше смысла.

на dict[key] = value представляет собой лучшую замену. Если я вижу этот код, я наполовину ожидаю, что ключ уже будет в словаре в любом случае.

один присваивает значение, а другой добавляет в словарь новый ключ и значение.