Почему собеседование по C# — это не экзамен, а диалог
Представьте: вы сидите напротив тимлида или senior-разработчика. Он смотрит на вас не как на врага, а как на будущего коллегу. Но в голове — туман, руки потеют, а на вопрос про IDisposable вы вдруг забываете, что это вообще такое. Знакомо?
Собеседование по C# — это не школьный тест, где нужно просто «угадать букву». Это проверка вашего инженерного мышления, умения рассуждать и, конечно, базовых знаний платформы .NET. В этой статье мы разберём главные темы, которые действительно спрашивают на интервью (спойлер: 80% вопросов повторяются из раза в раз).
База, которую нужно знать наизусть
Если вы едете на собеседование через час, а времени на подготовку нет — читайте этот раздел. Это «хлеб» C# разработчика. Без этих знаний вас не возьмут даже на junior.
1. Типы данных: Value vs Reference
Это, пожалуй, самый популярный вопрос. Интервьюер хочет услышать не просто «int — значимый, class — ссылочный». Ему важно, понимаете ли вы, как это работает под капотом.
// Пример, который часто дают на собеседовании
struct Point {
public int X;
public int Y;
}
class PointClass {
public int X;
public int Y;
}
void Main() {
Point p1 = new Point { X = 10, Y = 20 };
Point p2 = p1;
p2.X = 999;
Console.WriteLine(p1.X); // 10 — копия
PointClass pc1 = new PointClass { X = 10, Y = 20 };
PointClass pc2 = pc1;
pc2.X = 999;
Console.WriteLine(pc1.X); // 999 — ссылка
}
Ключевой момент: struct копируется целиком, class передаётся по ссылке. И да, string — это ссылочный тип, но ведёт себя как value из-за иммутабельности. Об этом тоже часто спрашивают.
2. Boxing и Unboxing
Простая тема, но её любят. Представьте, что вы кладёте value-тип (int) в object. Происходит упаковка (boxing). Когда забираете обратно — распаковка (unboxing). Это дорого по производительности.
int number = 42;
object boxed = number; // boxing
int unboxed = (int)boxed; // unboxing
В современных проектах это редкость, но знание механизма показывает, что вы понимаете, как .NET управляет памятью.
3. Интерфейсы и абстрактные классы
Классический вопрос: «Когда использовать interface, а когда abstract class?»
- Интерфейс — контракт. Если у вас есть разные классы, которые должны уметь делать одно и то же (например, летать: самолёт, птица, дрон).
- Абстрактный класс — базовая реализация. Если классы имеют общую логику (например, все животные дышат, но по-разному).
public interface IFlyable {
void Fly();
}
public abstract class Animal {
public abstract void MakeSound();
public void Breathe() => Console.WriteLine("Вдох-выдох");
}
В C# 8.0+ у интерфейсов появилась реализация по умолчанию, но на собеседовании лучше говорить про классический подход.
Продвинутые вопросы: где подвох
Когда база пройдена, интервьюер начинает «копать глубже». Вот темы, которые чаще всего вызывают ступор.
4. Async/Await и потоки
Многие путают асинхронность и многопоточность. Запомните: async/await — это про освобождение потока, а не про создание нового.
public async Task<string> GetDataAsync() {
using HttpClient client = new HttpClient();
// Поток освобождается, пока ждём ответ
string result = await client.GetStringAsync("https://example.com");
return result;
}
Часто спрашивают про ConfigureAwait(false). Ответ: это нужно, чтобы не возвращаться в исходный контекст синхронизации (например, в UI-потоке WPF). В библиотеках — всегда используйте, в приложениях — с осторожностью.
5. LINQ: от простого к сложному
LINQ — это не просто «Where и Select». Интервьюеры любят давать задачи на группировку, join и отложенное выполнение.
var numbers = new List<int> { 1, 2, 3, 4, 5, 6 };
// Классика: чётные числа в квадрате
var result = numbers
.Where(n => n % 2 == 0)
.Select(n => n * n)
.ToList();
// Подвох: отложенное выполнение
var query = numbers.Where(n => n > 2);
numbers.Add(10); // Добавили после создания запроса
Console.WriteLine(query.Count()); // 4, а не 3!
Важный момент: если не вызвать ToList() или ToArray(), запрос будет выполняться каждый раз заново. Это частая причина багов.
6. Паттерны проектирования: не просто названия
Недостаточно сказать «Singleton — это когда один экземпляр». Нужно показать, как вы его реализуете потокобезопасно.
public sealed class Singleton {
private static readonly Lazy<Singleton> _instance =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance => _instance.Value;
private Singleton() { }
}
Из других паттернов чаще всего спрашивают Factory, Strategy и Observer. Знать их нужно не как теорию, а как инструмент для решения реальных задач.
Алгоритмы и структуры данных: что реально спрашивают
Не пугайтесь — вас не попросят написать красно-чёрное дерево с закрытыми глазами. Но базовые алгоритмы знать нужно.
7. Reverse строки без встроенных методов
Классическая задача, которая проверяет понимание массивов и циклов.
public static string ReverseString(string input) {
char[] chars = input.ToCharArray();
int left = 0;
int right = chars.Length - 1;
while (left < right) {
(chars[left], chars[right]) = (chars[right], chars[left]);
left++;
right--;
}
return new string(chars);
}
Бонус: спросите, почему string нельзя менять напрямую (иммутабельность).
8. FizzBuzz и его вариации
Да, эту задачу дают даже senior-разработчикам, чтобы отсеять тех, кто не умеет писать код вообще.
for (int i = 1; i <= 100; i++) {
if (i % 15 == 0) Console.WriteLine("FizzBuzz");
else if (i % 3 == 0) Console.WriteLine("Fizz");
else if (i % 5 == 0) Console.WriteLine("Buzz");
else Console.WriteLine