Как пройти собеседование по C#: топ вопросов и ответы

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Как пройти собеседование по C#: топ вопросов и ответы

Собеседование на позицию C# / .NET разработчика — это не только проверка технических знаний, но и умение мыслить, объяснять сложные концепции простыми словами. В этой статье мы разобрали самые частые вопросы, которые задают на интервью, с примерами кода и пояснениями. Материал будет полезен как junior, так и middle разработчикам.

1. В чем разница между value types и reference types?

Это базовый, но важный вопрос. В C# все типы делятся на две категории:

  • Value types (типы значений) — хранятся в стеке, копируются при присваивании. Примеры: int, double, struct, enum.
  • Reference types (ссылочные типы) — хранятся в куче (heap), переменная хранит ссылку на объект. Примеры: class, string, array, delegate.

Пример для собеседования:

int a = 10;
int b = a;
b = 20;
Console.WriteLine(a); // 10 — значение не изменилось

var obj1 = new MyClass { Value = 10 };
var obj2 = obj1;
obj2.Value = 20;
Console.WriteLine(obj1.Value); // 20 — ссылка та же

На собеседовании также часто спрашивают про boxing/unboxing — преобразование value type в object и обратно. Старайтесь избегать этого в коде, так как это снижает производительность.

2. Что такое делегаты, события и лямбда-выражения?

Делегаты — это типы, которые хранят ссылки на методы. События — это обертка над делегатами, используемая для реализации паттерна "издатель-подписчик".

Пример делегата:

public delegate void MyDelegate(string message);

public static void ShowMessage(string msg) => Console.WriteLine(msg);

MyDelegate del = ShowMessage;
del("Hello from delegate");

Пример события:

public class Button
{
    public event EventHandler Click;
    public void Press() => Click?.Invoke(this, EventArgs.Empty);
}

Лямбда-выражения — это короткая запись анонимных методов. Они активно используются в LINQ:

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var even = numbers.Where(x => x % 2 == 0).ToList();

На собеседовании могут спросить: "Почему лучше использовать события, а не делегаты?" — ответ: события защищают список подписчиков от внешнего изменения (нельзя вызвать Invoke извне).

3. Как работает async/await и в чем отличие от многопоточности?

Это один из самых популярных вопросов. async/await — это синтаксический сахар для работы с асинхронными операциями. Он не создает новый поток, а эффективно использует существующий (поток UI или поток из пула).

Ключевые моменты:

  • async — модификатор метода, разрешающий использование await.
  • await — приостанавливает выполнение метода до завершения задачи, не блокируя поток.
  • Возвращаемый тип — обычно Task или Task<T>.

Пример:

public async Task<string> GetDataAsync()
{
    using var client = new HttpClient();
    string result = await client.GetStringAsync("https://api.example.com");
    return result;
}

Отличие от многопоточности: многопоточность (Thread, Task.Run) — это параллельное выполнение кода на нескольких ядрах CPU. Async/await — это асинхронность, которая освобождает поток для других задач во время ожидания (например, ответа от сервера).

Совет: на собеседовании приводите реальный пример — загрузка данных из сети или файла. Избегайте async void (кроме обработчиков событий) — это может привести к необработанным исключениям.

4. Что такое LINQ и как он работает под капотом?

LINQ (Language Integrated Query) — это набор методов расширения для работы с коллекциями. Он реализован через отложенное выполнение (deferred execution).

Пример запроса:

var result = products
    .Where(p => p.Price > 100)
    .OrderBy(p => p.Name)
    .Select(p => new { p.Name, p.Price });

Как работает: каждый метод возвращает IEnumerable<T>, который перечисляется только при вызове ToList(), ToArray() или в цикле foreach. Это позволяет строить цепочки запросов без лишних затрат памяти.

На собеседовании могут спросить про разницу между IEnumerable и IQueryable:

  • IEnumerable — выполняется в памяти (LINQ to Objects).
  • IQueryable — выполняется на стороне БД (LINQ to SQL, Entity Framework).

5. Как работает Garbage Collector (GC) и что такое поколения?

GC в .NET автоматически управляет памятью. Он работает в три поколения (gen 0, gen 1, gen 2):

  • Gen 0 — короткоживущие объекты (очищается чаще всего).
  • Gen 1 — буфер между gen 0 и gen 2.
  • Gen 2 — долгоживущие объекты (очищается редко).

Ключевые понятия:

  • Large Object Heap (LOH) — для объектов > 85 КБ. Сборка мусора на LOH может быть дорогой.
  • Dispose / IDisposable — для освобождения неуправляемых ресурсов (файлы, сокеты).
  • Finalization — деструкторы (финализаторы) вызываются перед сборкой, но замедляют GC.

Совет: используйте using для гарантированного вызова Dispose()

Блоги

Рекомендаций по книгам