← Назад к вопросам

Что такое Dictionary?

1.0 Junior🔥 291 комментариев
#Коллекции и структуры данных#Основы C# и .NET

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое Dictionary в C#?

Dictionary<TKey, TValue> — это универсальная коллекция в .NET, представляющая собой структуру данных "ключ-значение" (hash table), которая обеспечивает быстрый поиск, вставку и удаление элементов по уникальному ключу. Это один из наиболее часто используемых типов коллекций в C# для ассоциативного хранения данных.

Основные характеристики Dictionary:

  • Уникальность ключей: Каждый ключ в словаре должен быть уникальным. Попытка добавить дубликат ключа вызовет исключение ArgumentException.
  • Производительность: Операции поиска, добавления и удаления элементов выполняются близко к O(1) (константное время) в среднем случае, что делает словарь исключительно эффективным для частых операций доступа по ключу.
  • Порядок элементов: В стандартной реализации (Dictionary<TKey, TValue>) порядок элементов не гарантируется и может меняться при добавлении или удалении. Если требуется сохранение порядка вставки, используется OrderedDictionary или SortedDictionary<TKey, TValue> (который сортирует элементы по ключу).
  • Типизация: Благодаря поддержке обобщенных типов (generics), словарь обеспечивает строгую типизацию ключей и значений на этапе компиляции.

Типичное использование

Словарь идеально подходит для сценариев, где необходим быстрый доступ к данным по уникальному идентификатору (ключу). Примеры: кэширование объектов, хранение конфигураций, представление отношений "один-ко-многим" в памяти.

Базовые операции с Dictionary

Создание и инициализация

// Создание пустого словаря (ключ - int, значение - string)
Dictionary<int, string> users = new Dictionary<int, string>();

// Создание с указанием начальной емкости (оптимизация)
Dictionary<string, decimal> productPrices = new Dictionary<string, decimal>(capacity: 100);

// Инициализация при создании (C# 6.0+)
var countries = new Dictionary<string, string>
{
    {"RU", "Россия"},
    {"US", "Соединенные Штаты"},
    {"DE", "Германия"}
};

// Альтернативный синтаксис инициализации
var altCountries = new Dictionary<string, string>
{
    ["RU"] = "Россия",
    ["US"] = "США"
};

Добавление и обновление элементов

Dictionary<string, int> wordCount = new Dictionary<string, int>();

// Добавление элемента
wordCount.Add("hello", 1);

// Добавление или обновление через индексатор
wordCount["world"] = 1; // Добавит "world": 1
wordCount["hello"] = 5; // Обновит значение для "hello" на 5

// Безопасное добавление (если ключ еще не существует)
if (!wordCount.ContainsKey("newWord"))
{
    wordCount.Add("newWord", 1);
}

// Метод TryAdd (C# 8.0+) - добавляет только если ключа нет
bool added = wordCount.TryAdd("anotherWord", 10); // added = true
bool addedAgain = wordCount.TryAdd("anotherWord", 20); // addedAgain = false

Получение значений

// Прямой доступ через индексатор (выбрасывает KeyNotFoundException, если ключа нет)
int count = wordCount["hello"];

// Безопасный доступ через TryGetValue (рекомендуемый способ)
if (wordCount.TryGetValue("unknown", out int value))
{
    Console.WriteLine($"Значение найдено: {value}");
}
else
{
    Console.WriteLine("Ключ не найден");
}

// Проверка существования ключа
bool exists = wordCount.ContainsKey("hello");

Удаление элементов и перебор

// Удаление по ключу (возвращает true, если удаление успешно)
bool removed = wordCount.Remove("world");

// Очистка всего словаря
wordCount.Clear();

// Перебор всех элементов словаря
foreach (KeyValuePair<string, int> pair in wordCount)
{
    Console.WriteLine($"Ключ: {pair.Key}, Значение: {pair.Value}");
}

// Перебор только ключей или только значений
foreach (string key in wordCount.Keys) { /* ... */ }
foreach (int val in wordCount.Values) { /* ... */ }

Важные аспекты работы с Dictionary

  1. Выбор ключа: Ключ должен быть неизменяемым (immutable) или, по крайней мере, не меняться пока объект используется в качестве ключа. Для пользовательских типов необходимо корректно реализовать методы GetHashCode() и Equals().
  2. Исключения: Прямой доступ через индексатор dict[key] к несуществующему ключу вызывает KeyNotFoundException. Всегда предпочтительнее использовать TryGetValue().
  3. Потокобезопасность: Стандартный Dictionary<TKey, TValue> не является потокобезопасным. Для многопоточного доступа используйте ConcurrentDictionary<TKey, TValue> из пространства имен System.Collections.Concurrent.
  4. Емкость (Capacity): При создании словаря можно указать начальную емкость. Если известно приблизительное количество элементов, это позволяет избежать затратных операций перераспределения внутреннего хранилища при росте коллекции.
  5. Сравнение ключей: Поведение сравнения ключей можно задать через передачу компаратора IEqualityComparer<T> в конструктор словаря, что особенно полезно для строк с учетом или без учета регистра.

Практический пример

// Кэширование результатов вычислений
var calculationCache = new Dictionary<string, double>();

double CalculateExpensiveOperation(string parameters)
{
    // Пытаемся получить результат из кэша
    if (calculationCache.TryGetValue(parameters, out double cachedResult))
    {
        Console.WriteLine("Результат взят из кэша");
        return cachedResult;
    }
    
    // Дорогостоящее вычисление
    double result = /* ... длительные вычисления ... */;
    
    // Сохраняем результат в кэш для будущих запросов
    calculationCache[parameters] = result;
    Console.WriteLine("Результат вычислен и закэширован");
    
    return result;
}

Dictionary является фундаментальной структурой данных в арсенале C#-разработчика. Его правильное использование значительно повышает эффективность программ, особенно при работе с большими объемами данных, где требуется частый поиск по уникальным идентификаторам. Понимание его внутреннего устройства (хэш-таблицы) и особенностей использования критически важно для написания производительного и надежного кода.