Это все о слабой связи.
Представьте, что у вас есть класс foo, зависящий от класса bar
public class Foo
{
public Foo(Bar bar)
{
}
}
Здесь мы должны передать экземпляр bar в класс, чтобы создать его экземпляр. Что произойдет, если мы хотим иметь две разные реализации Bar, одну для взаимодействия с БД и одну для тестирования?
Ну, мы бы создали интерфейс IBar и использовали бы его вместо этого, тогда мы можем использовать две конкретные реализации.
Теперь рассмотрим, что у нас много сложных зависимостей во многих классах, которые вызываются во многих местах, если бы мы хотели изменить реализацию, нам пришлось бы менять код в каждом месте, где создается объект, реализующий IBar, это может быть много работы.
Вместо этого мы можем использовать инъекцию зависимости следующим образом.
IUnityContainer myContainer = new UnityContainer();
myContainer.RegisterType<IBar, Bar>();
Foo foo = myContainer.Resolve<Foo>();
Здесь платформа Unity вставила объект Bar в конструктор Foo. Если вы изменили регистрацию типов в одном месте, вы измените способ разрешения объектов Foo повсюду.
Если у вас сложные зависимости, которые могут измениться, DI необходим!