Внедрение зависимостей (DI) — это шаблон проектирования и фундаментальная концепция разработки программного обеспечения, включая программирование на C#. Он допускает слабую связь и разделение задач, позволяя внедрять зависимости в класс или компонент из внешнего источника.

В DI зависимости класса «внедряются» в него из внешних источников, а не создаются внутри самого класса. Это помогает отделить классы и делает их более пригодными для повторного использования, тестируемыми и модульными.

В DI вместо создания и управления зависимостями внутри класса или компонента зависимости предоставляются извне, обычно через параметры конструктора или установщики свойств. Это отделяет класс от его зависимостей, делая его более гибким, тестируемым и удобным в сопровождении.

Преимущества использования внедрения зависимостей в C# включают в себя:

  1. Развязка. DI помогает отделить компоненты, удаляя прямые зависимости и способствуя инверсии зависимостей. Это упрощает модификацию, замену или тестирование отдельных компонентов, не затрагивая всю систему.
  2. Тестируемость. С помощью внедрения зависимостей можно легко имитировать или заменять дубликаты тестов во время модульного тестирования. Это позволяет проводить более комплексное и изолированное тестирование, поскольку зависимости можно контролировать и управлять ими по мере необходимости.
  3. Повторное использование. Благодаря внедрению зависимостей компоненты становятся более пригодными для повторного использования. Их можно использовать в разных контекстах или сценариях, просто предоставляя разные реализации зависимостей.
  4. Удобство сопровождения:DI повышает удобство сопровождения кода за счет снижения сложности и зависимостей внутри классов. Изменения зависимостей можно вносить в одном месте, что упрощает их обновление или замену, не затрагивая всю кодовую базу.
  5. Гибкость.DI обеспечивает настройку во время выполнения и динамическое поведение. Зависимости можно легко поменять местами или настроить в зависимости от различных условий или сред выполнения.

Вот простой пример использования внедрения зависимостей в C#:

Допустим, у нас есть два класса, UserService и EmailService. Для UserService требуется экземпляр EmailService для отправки уведомлений по электронной почте.

public interface IEmailService
{
    void SendEmail(string recipient, string message);
}

public class EmailService : IEmailService
{
    public void SendEmail(string recipient, string message)
    {
        //Add logic to send email
        Console.WriteLine($"Sending email to {recipient}: {message}");
    }
}

public class UserService
{
    private readonly IEmailService _emailService;

    public UserService(IEmailService emailService)
    {
        _emailService = emailService;
    }

    public void RegisterUser(string username, string email)
    {
        //Add logic to register user

        //Send email notification
        _emailService.SendEmail(email, "Welcome to our platform!");
    }
}

В этом примере класс EmailService реализует интерфейс IEmailService. Класс UserService зависит от интерфейса IEmailService посредством внедрения конструктора.

Чтобы использовать эти классы, нам нужно настроить контейнер внедрения зависимостей. Вот пример использования встроенной платформы .NET Core Dependency Injection в ASP.NET с Dotnet 7.0:
Сначала установите пакет Nuget,

dotnet add package Microsoft.Extensions.DependencyInjection --version 7.0.0
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddTransient<IEmailService, EmailService>();

AddTransient<IEmailService, EmailService>(): этот вызов метода регистрирует интерфейс IEmailService с реализацией EmailService как временную зависимость. Переходный означает, что новый экземпляр службы будет создаваться каждый раз, когда он запрашивается.

Зарегистрировав IEmailService и EmailService в контейнере внедрения зависимостей, приложение теперь может разрешить зависимость IEmailService везде, где это необходимо, например, в контроллерах или других службах.

В этой конфигурации мы регистрируем EmailService как синглтон, а UserService как временную зависимость. Когда мы запрашиваем экземпляр UserService из контейнера, он автоматически разрешает зависимость IEmailService и внедряет ее в конструктор.

Используя внедрение зависимостей, мы достигаем слабой связи между UserService и EmailService. Мы можем легко заменить реализацию EmailService или предоставить другие реализации для целей тестирования, не изменяя класс UserService.

Примечание. Приведенный выше пример представляет собой упрощенную демонстрацию внедрения зависимостей в C#. В реальных приложениях вы обычно имеете более сложные зависимости и соответствующим образом настраиваете контейнер.

В C# DI можно реализовать с помощью различных платформ и библиотек, таких как встроенная платформа .NET Core Dependency Injection, сторонних библиотек, таких как Autofac, Ninject или Simple Injector, или даже путем создания вручную собственного контейнера DI.

Применяя DI в своих приложениях C#, вы можете получить более модульный, удобный в сопровождении и тестировании код, что приведет к повышению качества программного обеспечения и упрощению рабочих процессов разработки и обслуживания.

👋 Мое портфолио
🚀 Мой канал на Youtube
💻 Github