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

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


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

🧩 Как работают дженерики (generics) в .NET?

Typing SVG

Static Badge

✨ Оглавление

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


🔹 Что такое generics (коротко)

Generics — это параметризованные типы и методы. Вместо конкретного типа вы пишете параметр типа T (или несколько), и этот код работает для любого типа, соответствующего ограничениям. Примеры: List<T>, Dictionary<TKey, TValue>, void Swap<T>(ref T a, ref T b).

Зачем: типобезопасность + отказ от бокcинга для value-types + переиспользуемость кода.


🔹 Синтаксис — базовые формы

// generic класс
public class Box<T>
{
    public T Value { get; set; }
}

// generic метод
public static void Swap<T>(ref T a, ref T b) { var t = a; a = b; b = t; }

// generic интерфейс
public interface IRepository<T> { void Add(T item); T Get(int id); }

При вызове компилятор обычно выводит T автоматически:

var b = new Box<int> { Value = 5 }; // или просто new Box<int>()
Swap<int>(ref x, ref y); // тип можно явно указать

🔹 Reified generics (не как в Java) — что это даёт

Практическое следствие:


🔹 Как CLR/JIT реализует generics (важно для производительности)

Следствие:


🔹 Статические поля в generic-классе


🔹 Ограничения (constraints)

where T : ... — позволяет накладывать ограничения на типы-параметры.

Частые варианты:

Пример:

public T CreateInstance<T>() where T : class, new()
{
    return new T();
}

Частые вопросы:


🔹 default(T) и поведение для разных T


🔹 Variance — ковариантность и контрвариантность

Пример:

IEnumerable<string> ss = new List<string>();
IEnumerable<object> oo = ss; // OK — IEnumerable<out T> ковариантен

Проверки безопасности:


🔹 Generic methods vs generic types

public void Do<T>(T item) { ... }

🔹 Reflection и generics

Пример:

var open = typeof(Dictionary<,>);
var closed = open.MakeGenericType(typeof(string), typeof(int));

🔹 IL и вызовы на value-types (коротко, углубление)


🔹 Практические советы и производительность


🔹 Частые подводные камни (gotchas)


🔹 Короткие «правильные» ответы на часто задаваемые собес-вопросы

(коротко — для использования в интервью)


🔹 Примеры + шаблоны (полезно на собесе)

Generic repository

public interface IRepository<T> where T : IEntity
{
    void Add(T entity);
    T? Get(int id);
}

Generic singleton (статик per-T)

public static class SingletonHolder<T> where T : new()
{
    public static readonly T Instance = new T();
}

Covariant interface

public interface IReadOnlyList<out T>
{
    T Get(int index); // только возвращаем T — разрешено
}

Generic method with interface constraint

public T Max<T>(T a, T b) where T : IComparable<T>
    => a.CompareTo(b) >= 0 ? a : b;

🔹 «Каверзные» вопросы, которые могут задать — и краткий ответ

(сформулируй на собесе коротко — и можешь раскрыть, если попросят)

  1. «Generics в .NET — стираются или реальные?» ⇒ Реальные (reified). Метаданные сохраняют параметры типов.

  2. **«Почему List быстрее List при хранении int?»** ⇒ Потому что нет бокcинга: `List` хранит реальные int, JIT сгенерировал код для value-type.

  3. **«Можно ли присвоить List переменной List?»** ⇒ Нельзя. Generic классы не ковариантны. Используйте `IEnumerable` для ковариантности чтения.

  4. **«Сколько статических полей у GenericClass?»** ⇒ По одному на _каждую_ constructed-инстанцию (GenericClass и GenericClass — свои поля).

  5. «Можно ли использовать nullable типы с where T : struct?» ⇒ Нет — where T : struct запрещает nullable value types (ожидается non-nullable value type).

  6. «Что такое constrained. в IL?» ⇒ Это механизм CLR, позволяющий вызывать виртуальные/интерфейсные методы на value-type без бокcинга.

  7. «Почему иногда JIT шарит код для reference types?» ⇒ Для экономии нативного кода: одна версия кода способна обслуживать разные ссылочные типы.

  8. «Можно ли new T[size] внутри generic метода?» ⇒ Да, new T[n] разрешён (создаётся массив элементов типа T).

  9. «Equality for T — как правильно?» ⇒ Используйте EqualityComparer<T>.Default — он корректно обрабатывает value/reference types и пользовательские overrides.

  10. «Почему generic constraints влияют на производительность?» ⇒ Потому что наличие конкретных интерфейсных/методных ограничений позволяет компилятору/CLR генерировать эффективные вызовы (и избежать рефлексии/boxing).


🔹 Ещё пара продвинутых тем (если интервьюер уперся)


🔹 Резюме (что нужно знать джуну/мидлу/сеньору)


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

✨Dvurechensky✨