Что такое инверсия зависимостей в C#
Что проверяют
Отличаете ли вы принцип от техники. Инверсия зависимостей это буква D в наборе принципов SOLID, то есть правило о направлении ссылок между слоями. Внедрение зависимостей через конструктор и контейнер это лишь способ его соблюсти, и подмена одного другим на собеседовании слышна сразу.
Как отвечать
Формулировка: модули верхнего уровня не зависят от модулей нижнего уровня, оба зависят от абстракций; абстракции не зависят от деталей, детали зависят от абстракций.
Ключевая мысль, которую обычно теряют: инвертируется не только направление вызова, но и владение абстракцией. Интерфейс описан в терминах потребителя и лежит в его сборке, а инфраструктурный проект с базой, очередью и почтой ссылается на него, а не наоборот. Поэтому доменный проект не знает про конкретное хранилище вообще, а связывание реализаций происходит в одной точке сборки приложения.
public interface INotifier
{
Task NotifyAsync(OrderId id, CancellationToken ct);
}Дальше по практике: зависимость передаётся через конструктор, реализации регистрируются в контейнере, в тестах подставляется двойник без базы и без сети. Метод абстракции описывается на языке задачи (уведомить, сохранить заказ), а не на языке технологии.
Где спотыкаются
Ставят знак равенства между принципом и контейнером. Зарегистрировать в контейнере конкретный класс и получать его через конструктор можно, только зависимость от детали при этом никуда не делась.
Плодят интерфейсы механически, по одному на каждый класс, дословно повторяя его методы. Единственная реализация навсегда и интерфейс, повторяющий её сигнатуры, это не абстракция, а лишний файл. Абстракция уместна там, где есть выбор реализации или граница слоя.
Протаскивают инфраструктурные типы в сигнатуру: контекст базы, курсор драйвера, объект письма. Формально верхний слой зависит от интерфейса, фактически он по-прежнему знает про конкретную технологию, и заменить её без переписывания вызывающего кода не выйдет.