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

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

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

Начать курс

Введение

Собеседование на позицию C# разработчика — это не просто проверка синтаксиса. Работодатели хотят видеть понимание платформы .NET, принципов работы CLR, умение писать производительный код и знание современных подходов (async, LINQ, DI).

В этой статье мы разберем топ вопросов по C# от А до Я — от базовых типов данных до сложных тем вроде сборки мусора и асинхронного программирования. Каждый вопрос сопровождается кратким ответом и примером кода, чтобы вы могли уверенно чувствовать себя на интервью.

1. Базовые вопросы: типы, классы и память

1.1. В чем разница между Value Type и Reference Type?

Value Type (int, struct, enum) хранятся в стеке и копируются по значению. Reference Type (class, string, array) хранятся в куче, переменная содержит ссылку на объект.

int a = 10;
int b = a; // b — копия, a и b независимы

class MyClass { public int X; }
MyClass obj1 = new MyClass { X = 5 };
MyClass obj2 = obj1; // obj2 ссылается на тот же объект
obj2.X = 10; // obj1.X тоже станет 10

1.2. Что такое Boxing и Unboxing?

Boxing — упаковка значимого типа в объект (в кучу). Unboxing — обратный процесс. Частое использование снижает производительность.

int number = 42;
object boxed = number;    // Boxing
int unboxed = (int)boxed; // Unboxing

1.3. Расскажите про сборщик мусора (Garbage Collector).

GC в .NET автоматически освобождает память от объектов, на которые нет ссылок. Работает поколениями (Gen 0, 1, 2). Объекты больших размеров (>85 КБ) попадают в Large Object Heap (LOH).

Совет: Не вызывайте GC.Collect() вручную — это нарушает работу оптимизаций GC.

2. ООП и принципы проектирования

2.1. Объясните принципы SOLID.

  • S — Single Responsibility: класс должен иметь одну причину для изменения.
  • O — Open/Closed: открыт для расширения, закрыт для модификации.
  • L — Liskov Substitution: наследники должны корректно заменять базовый класс.
  • I — Interface Segregation: много маленьких интерфейсов лучше одного большого.
  • D — Dependency Inversion: зависимости должны быть от абстракций, а не от конкретных классов.

2.2. Что такое Dependency Injection (DI)?

DI — паттерн, при котором зависимости передаются в класс извне (через конструктор, метод или свойство). В .NET Core встроенный DI-контейнер.

public interface ILogger
{
    void Log(string message);
}

public class ConsoleLogger : ILogger
{
    public void Log(string message) => Console.WriteLine(message);
}

public class OrderService
{
    private readonly ILogger _logger;
    public OrderService(ILogger logger) // DI через конструктор
    {
        _logger = logger;
    }
}

3. LINQ, исключения и строки

3.1. Как работает LINQ? Что такое отложенное выполнение?

LINQ (Language Integrated Query) позволяет писать запросы к коллекциям, базам данных (EF Core) и XML. Отложенное выполнение означает, что запрос выполняется только при переборе результата (например, через foreach или .ToList()).

var numbers = new List<int> { 1, 2, 3, 4, 5 };
var query = numbers.Where(n => n > 2); // запрос не выполнен
numbers.Add(6); // добавляем после создания запроса
foreach (var n in query) // выполнение здесь
    Console.WriteLine(n); // 3, 4, 5, 6

3.2. В чем разница между String и StringBuilder?

String — неизменяемый тип. Каждая операция конкатенации создает новый объект. StringBuilder использует изменяемый буфер и эффективен для множественных изменений строки.

// Плохо (много аллокаций)
string s = "";
for (int i = 0; i < 1000; i++)
    s += i.ToString();

// Хорошо
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++)
    sb.Append(i);
string result = sb.ToString();

3.3. Как обрабатывать исключения? Что такое finally?

Используйте try-catch-finally. Блок finally выполняется всегда, даже если было исключение или return. Подходит для освобождения ресурсов.

FileStream file = null;
try
{
    file = File.OpenRead("data.txt");
    // работа с файлом
}
catch (FileNotFoundException ex)
{
    Console.WriteLine("Файл не найден");
}
finally
{
    file?.Close(); // гарантированно закроем файл
}

4. Продвинутые темы: async, делегаты, потоки

4.1. Как работает async/await? Что такое SynchronizationContext?

async/await — это синтаксический сахар над Task. Метод помечается async, а await приостанавливает выполнение метода до завершения асинхронной операции, не блокируя поток. SynchronizationContext восстанавливает контекст (например, UI-поток в WPF).

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

4.2. Что такое делегаты и события (delegate, event)?

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

public delegate void Notify(string message);

public class Publisher
{
    public event Notify OnNotify;
    
    public void Raise()
    {
        OnNotify?.Invoke("Событие сработало!");
    }
}

// Использование
Publisher pub = new Publisher();
pub.OnNotify += msg => Console.WriteLine(msg);
pub.Raise();

4.3. В чем разница между lock, Monitor и Semaphore?

  • lock — простейший механизм синхронизации

Блоги

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