Могут ли одинаковые значения использоваться в качестве ключа в словаре (Dictionary)?

Ответ

Нет, в стандартном Dictionary<TKey, TValue> каждый ключ должен быть уникальным. Попытка добавить запись с ключом, который уже существует, приведёт к исключению ArgumentException.

Пример ошибки:

var dict = new Dictionary<string, int>();
dict.Add("id", 1);
dict.Add("id", 2); // System.ArgumentException: An item with the same key has already been added.

Проверка и безопасное добавление: Перед добавлением следует проверять наличие ключа.

string key = "userId";
int value = 42;

if (!dict.ContainsKey(key))
{
    dict.Add(key, value);
}
// Или используйте индексер, который перезаписывает значение:
dict[key] = value; // Если ключ существовал - значение будет перезаписано.

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

var multiValueDict = new Dictionary<string, List<string>>();

// Вспомогательный метод для добавления
void AddToMultiDict(string key, string value)
{
    if (!multiValueDict.TryGetValue(key, out var list))
    {
        list = new List<string>();
        multiValueDict[key] = list;
    }
    list.Add(value);
}

AddToMultiDict("tags", "C#");
AddToMultiDict("tags", "dotnet");
// multiValueDict["tags"] содержит List<string> {"C#", "dotnet"}

Важно: Уникальность ключа определяется методами GetHashCode() и Equals() типа TKey. Для пользовательских типов, используемых в качестве ключа, эти методы должны быть корректно переопределены.

Ответ 18+ 🔞

Давай разжую эту тему, как будто я тебе на кухне объясняю, пока чайник кипит.

Смотри, с обычным Dictionary<TKey, TValue> всё просто, как два пальца об асфальт. Ключи там — уникальные, как отпечатки пальцев у нормального человека. Попробуешь добавить второй раз тот же самый ключ — получишь по ебалу исключением ArgumentException. Оно тебе прямо так и скажет: «Ты чё, мудила, этот ключ уже есть, я его помню!».

Вот, смотри, как это выглядит в коде, если ты совсем отбитый:

var myDict = new Dictionary<string, int>();
myDict.Add("id", 1);
myDict.Add("id", 2); // А тут тебе пиздец: System.ArgumentException

Как не получить по лбу? Есть два классических подхода, древних, как мир:

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

    string key = "userId";
    int value = 42;
    
    if (!myDict.ContainsKey(key)) // Если такого ключа ещё нет...
    {
        myDict.Add(key, value); // ...тогда добавляй спокойно.
    }
  2. Или просто дави его индексером. Это как прийти и сказать: «Отъебись, старое значение, теперь здесь будет новое». Если ключа не было — он создастся. Если был — значение просто перезапишется, и никто даже не пикнет.
    myDict[key] = value; // Всё просто, эффективно и без лишних телодвижений.

А если реально нужно по одному ключу несколько значений хранить? Ну, бывает же такое, что на одну вешалку десять пальто надо повесить. Тогда твой Dictionary превращается в шкаф, где на каждой вешалке висит не одна куртка, а целая вешалка-вертушка (список).

// Делаем словарь, где по строковому ключу будет висеть целый список строк.
var multiDict = new Dictionary<string, List<string>>();

// Метод-помощник, чтобы не повторять один и тот же код, как мантру.
void AddValue(string key, string newValue)
{
    // Пробуем получить список по ключу.
    if (!multiDict.TryGetValue(key, out var valueList))
    {
        // Если списка ещё нет — создаём его и кладём в словарь.
        valueList = new List<string>();
        multiDict[key] = valueList;
    }
    // А тут уже добавляем наше значение в найденный или свежесозданный список.
    valueList.Add(newValue);
}

// Используем.
AddValue("tags", "C#");
AddValue("tags", "dotnet");
AddValue("tags", "performance");
// Теперь multiDict["tags"] — это список из трёх элементов. Красота!

AddValue("admins", "Вася");
AddValue("admins", "Петя");
// И тут свой список. Всё чётко.

И последнее, о чём часто забывают, пока не прижмёт: уникальность ключей определяется через их GetHashCode() и Equals(). Если ты суёшь в качестве ключа свой собственный класс (типа User или TransactionId), то обязательно переопредели эти методы, а то получишь ебучую ситуацию, когда два одинаковых с твоей точки зрения объекта словарь будет считать разными ключами. Это пиздец как неочевидно бывает, когда дебажишь в три часа ночи.

Короче, запомни: хочешь уникальности и быстрого поиска — бери обычный словарь и следи за ключами. Нужно группировать хуёво-маё по какому-то признаку — делай словарь со списками. Всё гениальное просто.