Вопросы на собеседовании C#/.NET backend с ответами

Milad Bonakdar
Автор
Подготовьтесь к backend-собеседованию по C#/.NET: ASP.NET Core, EF Core, async, DI, REST API, тестирование и архитектура.
Введение
На backend-собеседовании по C#/.NET важно уметь объяснить, как вы строите API на ASP.NET Core, поддерживаете эффективный доступ к данным через EF Core, используете async-код без блокировки потоков и организуете сервисы через dependency injection. Сильный ответ связывает концепцию с реальным backend-компромиссом: производительность, надежность, тестируемость или поддерживаемость.
Используйте это руководство как практический чеклист. Прочитайте короткие ответы, а затем потренируйтесь связывать каждый из них с конкретным примером из проекта, стажировки, тестового задания или production-багa, который вы помогли решить.
Основы языка C#
1. В чем разница между struct и class в C#?
Ответ:
- Class (Класс): Ссылочный тип (размещается в куче). Когда вы передаете объект класса в метод, вы передаете ссылку на ячейку памяти. Изменения внутри метода влияют на исходный объект. Поддерживает наследование.
- Struct (Структура): Тип значения (размещается в стеке). Когда вы передаете структуру, передается копия данных. Изменения внутри метода не влияют на исходную структуру. Не поддерживает наследование (но может реализовывать интерфейсы).
- Использование: Используйте
structдля небольших, неизменяемых структур данных, представляющих одно значение (например,Point,Color). Используйтеclassдля большинства других объектов.
Распространенность: Часто Сложность: Легко
2. Объясните async и await. Как это помогает с масштабируемостью?
Ответ:
async и await позволяют методу приостановиться на время операции ввода-вывода и продолжить работу после завершения Task.
- Механизм:
awaitне создает новый поток. При вызовах базы данных, файловой системы или сети он освобождает поток запроса. - Масштабируемость: Это повышает throughput I/O-bound эндпоинтов ASP.NET Core, но не ускоряет CPU-bound работу.
- Совет для собеседования: Для database I/O упоминайте
CancellationTokenи методы EF Core вродеToListAsyncилиSaveChangesAsync.
Распространенность: Очень часто Сложность: Средне
3. Что такое Dependency Injection (DI) и как она реализована в .NET?
Ответ: Dependency Injection (Внедрение зависимостей) - это шаблон проектирования, в котором зависимости класса предоставляются извне, а не создаются внутри него.
- В .NET: ASP.NET Core имеет встроенный DI-контейнер. Вы регистрируете сервисы в
Program.cs(илиStartup.csв более старых версиях) и внедряете их через внедрение конструктора. - Времена жизни (Lifetimes):
- Transient: Создаются каждый раз, когда запрашиваются.
- Scoped: Создаются один раз для каждого запроса клиента (HTTP-запрос).
- Singleton: Создаются при первом запросе и используются всеми последующими запросами.
Распространенность: Очень часто Сложность: Средне
4. В чем разница между IEnumerable<T> и IQueryable<T>?
Ответ:
IEnumerable<T>: Выполняет запрос в памяти. При использовании с базой данных (EF Core) он извлекает все данные с сервера в память клиента и затем фильтрует их. Хорошо подходит для LINQ to Objects.IQueryable<T>: Выполняет запрос удаленно (например, на SQL-сервере). Он строит дерево выражений, которое преобразуется в SQL-запрос. Фильтрация происходит на стороне базы данных, что гораздо эффективнее для больших наборов данных.
Распространенность: Часто Сложность: Средне
5. Что такое Extension Methods (Методы расширения)?
Ответ: Методы расширения позволяют "добавлять" методы к существующим типам без создания нового производного типа, перекомпиляции или иного изменения исходного типа.
- Синтаксис: Определяются как статические методы в статическом классе. Первый параметр указывает, с каким типом работает метод, и ему предшествует ключевое слово
this. - Пример: Добавление метода
WordCount()к классуstring.
Распространенность: Часто Сложность: Легко
ASP.NET Core и архитектура
6. Что такое Middleware (Промежуточное ПО) в ASP.NET Core?
Ответ: Middleware - это программные компоненты, которые собираются в конвейер приложения для обработки запросов и ответов.
- Конвейер: Каждый компонент выбирает, передавать ли запрос следующему компоненту в конвейере, и может выполнять работу до и после вызова следующего компонента.
- Примеры: Аутентификация, Авторизация, Ведение журнала, Обработка исключений, Обслуживание статических файлов.
- Порядок важен: Порядок, в котором промежуточное ПО добавляется в
Program.cs, определяет порядок выполнения.
Распространенность: Очень часто Сложность: Средне
7. Объясните разницу между .NET Core и .NET Framework.
Ответ:
- .NET Framework: Оригинальная реализация только для Windows. Зрелая, но привязана к Windows.
- .NET Core / современный .NET: Кроссплатформенная open-source линия-преемник. Начиная с .NET 5 платформу обычно называют просто
.NET; текущие релизы включают .NET 10 LTS с поддержкой C# 14. - Ключевые различия: Современный .NET обычно выбирают для новых backend API, потому что он поддерживает Linux-контейнеры, параллельные версии, актуальные возможности ASP.NET Core и активные улучшения runtime.
Распространенность: Часто Сложность: Легко
8. Что такое Kestrel?
Ответ: Kestrel - это кроссплатформенный веб-сервер с открытым исходным кодом, управляемый событиями, который включен по умолчанию в шаблоны ASP.NET Core.
- Роль: Он прослушивает HTTP-запросы и передает их приложению.
- Использование: Он может работать автономно (пограничный сервер) или за обратным прокси-сервером, таким как IIS, Nginx или Apache. Использование обратного прокси-сервера рекомендуется для производственной среды для обработки безопасности, балансировки нагрузки и завершения SSL.
Распространенность: Средне Сложность: Средне
9. Как вы обрабатываете глобальную обработку исключений в ASP.NET Core?
Ответ: Вместо блоков try-catch в каждом контроллере следует использовать промежуточное ПО для глобальной обработки исключений.
UseExceptionHandler: Встроенное промежуточное ПО, которое перехватывает исключения, регистрирует их и повторно выполняет запрос в альтернативном конвейере (обычно указывающем на страницу ошибок или ответ API).- Пользовательское промежуточное ПО: Вы можете написать пользовательское промежуточное ПО для перехвата исключений и возврата стандартизированного JSON-ответа об ошибке (например,
ProblemDetails).
Распространенность: Часто Сложность: Средне
База данных и Entity Framework
10. Что такое Entity Framework Core (EF Core)? Code-First vs. Database-First?
Ответ: EF Core - это Object-Relational Mapper (ORM) для .NET. Он позволяет разработчикам работать с базой данных, используя объекты .NET.
- Code-First (Сначала код): Вы сначала определяете свои доменные классы (сущности), а EF Core создает/обновляет схему базы данных на основе их с использованием миграций. Предпочтительнее для новых проектов.
- Database-First (Сначала база данных): У вас есть существующая база данных, и EF Core генерирует классы .NET (scaffolding) на основе схемы.
Распространенность: Часто Сложность: Легко
11. Что такое проблема N+1 в EF Core и как ее исправить?
Ответ: Проблема N+1 возникает, когда вы загружаете список сущностей, а затем в цикле подгружаете связанную сущность для каждого элемента, создавая много дополнительных запросов.
- Исправление: Загружайте связанные данные осознанно через
Include, filtered include, projection или explicit loading. В критичных путях избегайте lazy loading. - Пример:
await context.Orders.Include(o => o.Customer).ToListAsync(); - Компромисс: Для нескольких коллекций рассмотрите split queries или projection, чтобы избежать cartesian explosion и лишних колонок.
Распространенность: Очень часто Сложность: Средне
12. Объясните шаблон Repository (Репозиторий). Зачем использовать его с EF Core?
Ответ: Шаблон Repository выступает посредником между уровнями домена и сопоставления данных, используя интерфейс, подобный коллекции, для доступа к доменным объектам.
- Плюсы: Отделяет приложение от конкретной технологии доступа к данным (EF Core), упрощает модульное тестирование (можно имитировать репозиторий) и централизует логику доступа к данным.
- Минусы/Дискуссия:
DbContextEF Core уже является реализацией шаблона Repository/Unit of Work. Добавление еще одного уровня иногда может быть избыточным ("абстракция над абстракцией").
Распространенность: Часто Сложность: Сложно
REST API и веб-сервисы
13. Что такое HTTP Verbs (Методы HTTP) и их типичное использование?
Ответ:
- GET: Получить ресурс. Безопасный и идемпотентный.
- POST: Создать новый ресурс. Не идемпотентный.
- PUT: Обновить/Заменить существующий ресурс. Идемпотентный.
- PATCH: Частично обновить ресурс. Не обязательно идемпотентный (но обычно да).
- DELETE: Удалить ресурс. Идемпотентный.
Распространенность: Часто Сложность: Легко
14. В чем разница между 401 Unauthorized и 403 Forbidden?
Ответ:
- 401 Unauthorized: Пользователь не аутентифицирован. Клиент должен войти в систему и повторить попытку. "Я не знаю, кто ты."
- 403 Forbidden: Пользователь аутентифицирован, но не имеет разрешения на доступ к ресурсу. "Я знаю, кто ты, но ты не можешь этого сделать."
Распространенность: Часто Сложность: Легко
Тестирование и лучшие практики
15. В чем разница между Unit Tests (Модульные тесты) и Integration Tests (Интеграционные тесты)?
Ответ:
- Unit Tests: Тестируют небольшую единицу кода (обычно метод) изолированно. Зависимости имитируются (с использованием таких инструментов, как Moq). Быстрые и надежные.
- Integration Tests: Тестируют, как разные части приложения работают вместе (например, конечная точка API + база данных). Медленнее, но проверяют фактическое поведение системы.
Распространенность: Часто Сложность: Легко
16. Как вы имитируете (Mock) зависимости в модульных тестах?
Ответ: Фреймворки имитации, такие как Moq или NSubstitute, используются для создания поддельных реализаций интерфейсов.
- Цель: Изолировать тестируемый класс. Например, при тестировании
UserServiceвы имитируетеIUserRepository, чтобы не обращаться к реальной базе данных. - Пример (Moq):
Распространенность: Часто Сложность: Средне
17. Что такое SOLID принципы? Приведите пример одного из них.
Ответ: SOLID - это акроним для 5 принципов проектирования, которые делают программное обеспечение более понятным, гибким и поддерживаемым.
- Single Responsibility Principle (SRP) - Принцип единственной ответственности
- Open/Closed Principle (OCP) - Принцип открытости/закрытости
- Liskov Substitution Principle (LSP) - Принцип подстановки Лисков
- Interface Segregation Principle (ISP) - Принцип разделения интерфейсов
- Dependency Inversion Principle (DIP) - Принцип инверсии зависимостей
- Пример (DIP): Модули высокого уровня не должны зависеть от модулей низкого уровня. Оба должны зависеть от абстракций. Это основа для Dependency Injection (Внедрения зависимостей).
Распространенность: Часто Сложность: Сложно
18. Что такое Boxing и Unboxing? Почему этого следует избегать?
Ответ:
- Boxing (Упаковка): Преобразование типа значения (например,
int) в ссылочный тип (object). Он выделяет память в куче. - Unboxing (Распаковка): Преобразование ссылочного типа обратно в тип значения.
- Производительность: Обе операции являются дорогостоящими (выделение памяти, проверка типа). Generics (
List<T>) помогают избежать упаковки/распаковки по сравнению со старыми коллекциями (ArrayList).
Распространенность: Часто Сложность: Средне
19. Что такое оператор using в C#?
Ответ:
Оператор using предоставляет удобный синтаксис, обеспечивающий правильное использование объектов IDisposable.
- Механизм: Он автоматически вызывает метод
Dispose()для объекта при выходе из блока (даже если возникает исключение). - Современный синтаксис:
using var file = File.OpenRead("path");(фигурные скобки не нужны, удаляется в конце области видимости).
Распространенность: Часто Сложность: Легко
20. Объясните концепцию Middleware в контексте шаблона "Chain of Responsibility" (Цепочка обязанностей).
Ответ: ASP.NET Core Middleware является классической реализацией шаблона Chain of Responsibility.
- Шаблон: Запрос передается по цепочке обработчиков. Каждый обработчик решает, либо обработать запрос, либо передать его следующему обработчику в цепочке.
- Применение: В .NET
RequestDelegateпредставляет следующий обработчик. Компоненты Middleware объединяются в цепочку для формирования конвейера запросов.
Распространенность: Нечасто Сложность: Сложно


