Ответ
Класс Map<TKey, TValue> (или Dictionary) — это коллекция, хранящая пары «ключ-значение» и обеспечивающая быстрый доступ по ключу. Его базовая реализация включает следующие обязательные и опциональные компоненты.
Базовая реализация с использованием хеш-таблицы (аналог Dictionary<TKey, TValue>):
public class Map<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
{
// 1. Внутреннее хранилище данных
private readonly Dictionary<TKey, TValue> _storage;
// 2. Конструкторы
public Map()
{
_storage = new Dictionary<TKey, TValue>();
}
public Map(IEqualityComparer<TKey> comparer)
{
_storage = new Dictionary<TKey, TValue>(comparer);
}
// 3. Основные операции
public void Add(TKey key, TValue value)
{
if (key == null) throw new ArgumentNullException(nameof(key));
if (_storage.ContainsKey(key)) throw new ArgumentException("Key already exists.");
_storage.Add(key, value);
}
public bool TryAdd(TKey key, TValue value)
{
return _storage.TryAdd(key, value); // Доступно в .NET Core 3.0+
}
public bool TryGetValue(TKey key, out TValue value)
{
return _storage.TryGetValue(key, out value);
}
public bool ContainsKey(TKey key)
{
return _storage.ContainsKey(key);
}
public bool Remove(TKey key)
{
return _storage.Remove(key);
}
public void Clear()
{
_storage.Clear();
}
// 4. Индексатор для удобного доступа (как у массива)
public TValue this[TKey key]
{
get => _storage[key];
set => _storage[key] = value; // Добавляет или обновляет значение
}
// 5. Свойства для метаинформации
public int Count => _storage.Count;
public ICollection<TKey> Keys => _storage.Keys;
public ICollection<TValue> Values => _storage.Values;
// 6. Реализация IEnumerable для поддержки foreach и LINQ
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return _storage.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Ключевые аспекты реализации и проектирования:
-
Выбор структуры данных:
- Хеш-таблица (
Dictionary) — O(1) в среднем для вставки и поиска, но требует хорошей хеш-функции для ключей. - Сбалансированное дерево (например,
SortedDictionary) — O(log n) для операций, но хранит ключи в отсортированном порядке.
- Хеш-таблица (
-
Сравнение ключей: Критически важно правильно определить равенство ключей. Для пользовательских типов (
TKey) необходимо переопределитьGetHashCode()иEquals()или предоставить кастомныйIEqualityComparer<TKey>в конструктор. -
Потокобезопасность: Базовая реализация не является потокобезопасной. Для многопоточного доступа потребуется использование примитивов синхронизации (
lock,ConcurrentDictionary). -
Null-обработка: Нужно четко определить политику: разрешать
nullв качестве ключа или значения? В примере выше ключ не может бытьnull.
Пример использования:
var userMap = new Map<int, string>();
userMap.Add(1, "Alice");
userMap[2] = "Bob"; // Использование индексатора
if (userMap.TryGetValue(1, out var userName))
{
Console.WriteLine(userName); // "Alice"
}
foreach (var kvp in userMap) // Благодаря IEnumerable
{
Console.WriteLine($"ID: {kvp.Key}, Name: {kvp.Value}");
}