JavaRush /Курсы /C# SELF /Контракт на словарь: IDict...

Контракт на словарь: IDictionary<TKey, TValue>

C# SELF
28 уровень , 4 лекция
Открыта

1. Введение

Давайте представим: вы устраиваетесь на работу в секретную лабораторию по изучению котиков. Вам дают задачу — создать электронный словарь котиков, где по кличке можно быстро узнать возраст, цвет и размер хвоста кота. Готовое решение уже есть — это Dictionary<string, Cat>. Но вот беда: позднее начальник говорит, что для некоторых редких пород нужно, чтобы словарь поддерживал сохранение порядка добавления, а иногда ещё и удалялся по особой логике.

А что если вам нужно написать метод, который будет принимать любой «кошачий словарь»? Неважно, какой конкретно класс — важно, чтобы он поддерживал основные операции «ключ-значение». Вот здесь вступает в игру интерфейс IDictionary<TKey, TValue>.

IDictionary<TKey, TValue> — это общий контракт, который определяет, что такое словарь в .NET. Это не конкретный класс, а интерфейс, то есть набор правил, которые должен поддерживать любой настоящий словарь:

  • Быстрый поиск по ключу
  • Добавление, удаление пар «ключ-значение»
  • Перебор всех пар
  • Проверка наличия ключа

Если бы Java существовала в Средневековье, её рыцари вместо мечей против драконов размахивали бы ключами и значениями. А C#-разработчики просто реализовали бы IDictionary<TKey, TValue> — и дракон (то есть ваш код) был бы повержен.

2. Таблица интерфейса IDictionary

Давайте посмотрим на основные "обещания" (члены) этого интерфейса:

Член интерфейса Тип Описание
this[TKey key]
Свойство Индексатор. Позволяет получать или устанавливать значение, связанное с указанным ключом. При чтении: если ключ не найден, выбрасывает KeyNotFoundException. При записи: если ключ не найден, добавляет новую пару; если ключ существует, обновляет значение. Важно: это самый частый способ работы со словарями.
ICollection<TKey> Keys
Свойство Возвращает коллекцию, содержащую все ключи в словаре. Позволяет перебирать только ключи.
ICollection<TValue> Values
Свойство Возвращает коллекцию, содержащую все значения в словаре. Позволяет перебирать только значения.
Add(TKey key, TValue value)
Метод Добавляет указанный ключ и значение в словарь. Если ключ уже существует, генерирует ArgumentException.
ContainsKey(TKey key)
Метод Определяет, содержит ли словарь элемент с указанным ключом. Возвращает true, если ключ найден; в противном случае — false. Это очень полезно, чтобы избежать ошибок при попытке обратиться к несуществующему ключу через индексатор.
Remove(TKey key)
Метод Удаляет элемент с указанным ключом из словаря. Возвращает true, если элемент успешно найден и удален; в противном случае — false (например, если ключ не был найден).
TryGetValue(TKey key, out TValue value)
Метод Получает значение, связанное с указанным ключом. Это безопасный способ получить значение, если вы не уверены, существует ли ключ. Возвращает true, если ключ найден, и value содержит соответствующее значение; в противном случае — false, и value будет содержать значение по умолчанию для TValue. Этот метод не выбрасывает исключение, что делает его очень популярным в реальном коде.

3. Основные члены интерфейса IDictionary<TKey, TValue>

А теперь — к самому важному! Посмотрим, что внутри интерфейса IDictionary<TKey, TValue>, и научимся пользоваться этим «контрактом» в вашем коде.


public interface IDictionary<TKey, TValue> : ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>
{
    TValue this[TKey key] { get; set; } // Индексатор для доступа по ключу
    ICollection<TKey> Keys { get; }
    ICollection<TValue> Values { get; }
    void Add(TKey key, TValue value); // Добавить новую пару (ключ не должен существовать) 
    bool ContainsKey(TKey key); // Есть ли такой ключ?
    bool Remove(TKey key); // Удалить по ключу
    bool TryGetValue(TKey key, out TValue value); // Безопасно получить значение
}

Давайте разберём основные моменты:

Индексатор [key]

Позволяет получать и задавать значения по ключу:

dictionary["Барсик"] = new Cat("Барсик", 2);

Свойства Keys и Values

Позволяют получить коллекцию всех ключей или всех значений в словаре.

foreach (var name in dictionary.Keys)
{
    Console.WriteLine(name);
}

Методы Add, Remove, ContainsKey, TryGetValue

  • Add(key, value) — добавить новую пару
  • Remove(key) — удалить по ключу
  • ContainsKey(key) — проверить наличие ключа
  • TryGetValue(key, out value) — безопасно получить значение (без исключения, если ключа нет)

4. Использование IDictionary<TKey, TValue> на практике

Универсальные методы

Допустим, вы пишете функцию, которая должна работать со словарём, но не хочет знать, какой класс внутри: обычный Dictionary, SortedDictionary, или вдруг кто-то реализовал свой собственный «криптоколлективный словарь».

Вы объявляете параметр типа IDictionary<TKey, TValue>:


static void PrintDictionary<TKey, TValue>(IDictionary<TKey, TValue> someDictionary)
{
    foreach (var pair in someDictionary)
    {
        Console.WriteLine($"{pair.Key}: {pair.Value}");
    }
}

Теперь ваш метод принимает любой словарь! Под капотом может быть что угодно — даже словарь, который шифрует значения, если вам настолько весело в жизни.

Использование IDictionary для передачи параметров

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


void SetCatParameters(IDictionary<string, string> parameters)
{
    if (parameters.ContainsKey("color"))
    {
        Console.WriteLine($"Покрасьте котика в цвет: {parameters["color"]}");
    }
}

Единая сигнатура — несколько реализаций

Поясним на живой таблице:

Класс коллекции Реализует IDictionary<TKey,TValue> Особенности
Dictionary<TKey, TValue>
✅ Да Быстрый поиск, ключи в произвольном порядке
SortedDictionary<TKey,TValue>
✅ Да Ключи автоматически сортируются
SortedList<TKey, TValue>
✅ Да Ключи сортируются, более экономно по памяти
(Свой класс, реализующий интерфейс) ✅ Да Любая ваша логика, но обязаны соблюдать контракт

5. Связь с другими интерфейсами коллекций

Для настоящих гиков: интерфейс IDictionary<TKey, TValue> наследуется от ICollection<KeyValuePair<TKey, TValue>> и IEnumerable<KeyValuePair<TKey, TValue>>. Это значит, что любой словарь можно:

  • Перебирать через foreach по парам ключ-значение,
  • Добавлять и удалять пары с помощью методов коллекции,
  • Получать количество элементов.

foreach (var entry in myDictionary)
{
    Console.WriteLine($"{entry.Key} => {entry.Value}");
}

6. Особенности и типичные ошибки

Работа с индексатором

Самая частая ошибка новичков: попытка получить элемент по отсутствующему ключу вызовет исключение KeyNotFoundException.


var value = myDictionary["НемаТакогоКлюча"]; // Boom!

Поэтому всегда лучше использовать TryGetValue:


if (myDictionary.TryGetValue("Мурзик", out var cat))
{
    Console.WriteLine($"Нашли котика: {cat}");
}
else
{
    Console.WriteLine($"Котика не найдено!");
}

Добавление уже существующего ключа

Если вызвать Add для ключа, который уже есть, получите ArgumentException. Если хотите «добавлять или обновлять», используйте индексатор:


// Добавляет если нет, обновляет если есть
myDictionary["Мурка"] = new Cat("Мурка", 5);

Перебор и модификация

Не пытайтесь модифицировать словарь (например, удалять элементы) в цикле foreach напрямую: получите исключение. Если нужно удалить что-то, сначала соберите список ключей для удаления, а потом удаляйте их в отдельном цикле:


// Безопасный способ удаления элементов
var keysToRemove = new List<string>();
foreach (var pair in myDictionary)
{
    if (pair.Value.Age > 10) // Условие для удаления
    {
        keysToRemove.Add(pair.Key);
    }
}

foreach (var key in keysToRemove)
{
    myDictionary.Remove(key);
}
2
Задача
C# SELF, 28 уровень, 4 лекция
Недоступна
Проверка наличия ключа в словаре
Проверка наличия ключа в словаре
1
Опрос
Контракт на коллекцию, 28 уровень, 4 лекция
Недоступен
Контракт на коллекцию
Основные интерфейсы коллекций
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Slevin Уровень 34
9 февраля 2026
Если бы Java существовала в Средневековье, её рыцари вместо мечей против драконов размахивали бы ключами и значениями. А C#-разработчики просто реализовали бы IDictionary<TKey, TValue> — и дракон (то есть ваш код) был бы повержен. Всё. Пошла шиза у нашего ИИ... К котикам претензий, понятное дело, нет. Это святое! 🐈