Коллекция вопросов ❓ на собеседовании в C# 🍧

Обзор вопросов по языка програмиированию C# и технологии NET


Project maintained by Dvurechensky-Docs Hosted on GitHub Pages — Theme by mattgraham

🔑 Что делает метод `GetHashCode()` и зачем он нужен?

Typing SVG

Static Badge

✨ Оглавление

⬆ Вернуться к главной


1️⃣ Основная идея


2️⃣ Контракт метода

Microsoft рекомендует соблюдать несколько правил:

  1. Согласованность

    • Если два объекта равны (по Equals), то их GetHashCode() должны совпадать.
  2. Необязательная уникальность

    • Неравные объекты могут иметь одинаковый хэш-код.
  3. Стабильность

    • Хэш-код объекта не должен меняться, пока объект находится в хэш-коллекции.
    • Если объект изменяется так, что Equals меняется, хэш-код тоже должен меняться соответствующе, иначе коллекции станут неконсистентными.

Пример:

var dict = new Dictionary<Person, string>();
var p1 = new Person("John", 30);
dict[p1] = "Engineer";

p1.Age = 31; // если Age участвует в Equals/GetHashCode
// dict[p1] теперь может не найтись в коллекции

3️⃣ Встроенные реализации


4️⃣ Когда вызывается GetHashCode()

  1. Коллекции с хэшированием

    • Dictionary<TKey, TValue> и HashSet<T> используют хэш-коды для быстрого поиска.
    • Хэш-код определяет корзину (bucket), куда помещается объект.
  2. Операции Contains, Remove

    • Сначала проверяется хэш-код, затем Equals для подтверждения.
  3. LINQ и другие алгоритмы

    • Некоторые алгоритмы могут использовать хэширование для объединения (Distinct, GroupBy).

5️⃣ Как работает под капотом

Пример для Dictionary<TKey,TValue>:

  1. GetHashCode() → целое число.
  2. Хэш-код преобразуется в индекс массива (bucket index) через hash % buckets.Length.
  3. В bucket могут быть несколько элементов → проверяется Equals.

Важное:


6️⃣ Переопределение GetHashCode()

class Person
{
    public string Name { get; }
    public int Age { get; }

    public override bool Equals(object obj) =>
        obj is Person p && p.Name == Name && p.Age == Age;

    public override int GetHashCode() =>
        HashCode.Combine(Name, Age);
}

7️⃣ Каверзные моменты для собеса

  1. Обязательность переопределения

    • Если переопределяешь Equals, обязательно переопределять GetHashCode.
  2. Mutable ключи

    • Неиспользуемые ключи в хэш-коллекциях, которые изменяются, ломают поиск.
  3. Коллизии

    • Коллизии возможны → коллекции корректно их обрабатывают, но поиск чуть медленнее.
  4. Ссылочные типы без переопределения

    • Хэш-код основан на ссылке, а не на содержимом.
  5. Стабильность

    • В разных запусках приложения .NET Core 3+ может возвращать разные хэши для string (для защиты от DoS атак).

8️⃣ Производительность


9️⃣ Примеры использования

Для Dictionary

var dict = new Dictionary<Person, string>();
dict[new Person("Alice", 25)] = "Engineer";

var key = new Person("Alice", 25);
Console.WriteLine(dict.ContainsKey(key)); // true, если Equals и GetHashCode согласованы

Для HashSet

var set = new HashSet<string>();
set.Add("Hello");
set.Add("Hello"); // не добавит повторно

Для Distinct

var numbers = new List<int> {1,2,2,3};
var distinct = numbers.Distinct(); // использует GetHashCode + Equals

🔟 Вопросы на собеседовании

  1. Что делает GetHashCode()? Возвращает целое число для хэширования объекта, используемое в хэш-коллекциях.

  2. Что важнее: Equals() или GetHashCode()? Они связаны: если Equals переопределён, GetHashCode должен быть согласован.

  3. Можно ли использовать изменяемый объект в качестве ключа Dictionary? Нельзя, если хэш-код зависит от изменяемых полей.

  4. Что такое коллизия? Два разных объекта имеют одинаковый хэш-код.

  5. Почему хэш-код объекта может изменяться между запусками приложения? В .NET Core строки используют случайное смещение для защиты от атак DoS.

  6. Как безопасно реализовать GetHashCode() для нескольких полей? Использовать HashCode.Combine(field1, field2, ...).

  7. Что произойдёт, если не переопределить GetHashCode() при переопределении Equals()? Хэш-коллекции могут работать некорректно (не смогут найти объект по ключу).


⬆ Вернуться к главной

✨Dvurechensky✨