0Pricing
C# Academy · Урок

Основы контейнера внедрения зависимостей

Разберитесь в инверсии управления, регистрации служб и разрешении зависимостей контейнером внедрения зависимостей .NET.

«Основы контейнера внедрения зависимостей» — бесплатный урок C# Academy на CoddyKit. Это урок 1 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения C# Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс C# Academy содержит 4 уроков всего.

Что такое внедрение зависимостей

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

Вместо того чтобы писать var repo = new UserRepository(); внутри класса, класс объявляет, что ему нужно, а DI-контейнер предоставляет эти зависимости.

Инверсия управления

DI — это конкретная реализация принципа инверсии управления: управление созданием зависимостей передаётся от зависимого класса внешнему контейнеру.

Это упрощает тестирование и замену классов.

Настройка контейнера DI в .NET

В приложении .NET контейнер DI настраивается с помощью IServiceCollection в Program.cs. Сервисы регистрируются, а затем извлекаются средой выполнения.

var builder = WebApplication.CreateBuilder(args);

// Register services
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<UserService>();

var app = builder.Build();
app.Run();

Определение интерфейса и реализации

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

public interface IUserRepository
{
    User? GetById(int id);
}

public class UserRepository : IUserRepository
{
    public User? GetById(int id)
    {
        // fetch from database
        return new User { Id = id, Name = "Alice" };
    }
}

Получение служб через конструктор

Контейнер автоматически внедряет зарегистрированные службы в конструкторы. Классу достаточно объявить нужный ему интерфейс — ключевое слово new не требуется.

public class UserService
{
    private readonly IUserRepository _repo;

    public UserService(IUserRepository repo)
    {
        _repo = repo;
    }

    public User? FindUser(int id) => _repo.GetById(id);
}

Регистрация нескольких служб

Вы можете зарегистрировать столько служб, сколько необходимо. Часто используются методы расширения AddTransient, AddScoped и AddSingleton — каждый из них задаёт свой срок действия.

builder.Services.AddSingleton<IConfig, AppConfig>();
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddTransient<IEmailService, SmtpEmailService>();
builder.Services.AddScoped<UserService>();

Прямое использование поставщика служб

В редких случаях службы необходимо получать императивно. IServiceProvider позволяет вызвать GetRequiredService<T>() для получения службы, но в большинстве случаев предпочтительно внедрение через конструктор.

// Anti-pattern (service locator) — use sparingly
public class ManualResolver
{
    private readonly IServiceProvider _sp;

    public ManualResolver(IServiceProvider sp) => _sp = sp;

    public void DoWork()
    {
        var svc = _sp.GetRequiredService<UserService>();
        svc.FindUser(1);
    }
}

Регистрация открытых обобщений

.NET DI поддерживает регистрацию открытых обобщённых типов. Вы можете один раз зарегистрировать IRepository<>, после чего он будет разрешаться в Repository<T> для любого типа сущности.

builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));

// Resolves as:
// IRepository<User> -> Repository<User>
// IRepository<Order> -> Repository<Order>

Проверка при запуске

С помощью ValidateOnStart() или ValidateScopes = true контейнер может обнаружить неправильно настроенные регистрации (например, удержание службы с областью действия внутри одиночной службы) при запуске приложения, а не во время выполнения.

builder.Services.AddScoped<IMyService, MyService>();

// Detect scope violations at startup
builder.Host.UseDefaultServiceProvider(options =>
{
    options.ValidateScopes = true;
    options.ValidateOnBuild = true;
});

Декорирование служб

Вы можете обернуть службу декоратором, не изменяя исходный класс. Сначала зарегистрируйте внутреннюю службу, а затем декоратор, который её оборачивает.

builder.Services.AddScoped<IUserRepository, UserRepository>();

// Decorator pattern
builder.Services.Decorate<IUserRepository, CachedUserRepository>();
// Requires Scrutor NuGet package

Практический пример: минимальный API с DI

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

app.MapGet("/users/{id}", (int id, UserService svc) =>
{
    var user = svc.FindUser(id);
    return user is null ? Results.NotFound() : Results.Ok(user);
});

Быстрая проверка

Какой способ получения зависимостей следует предпочитать в большинстве классов?

Итоги: основы контейнера DI

Главное:

  • DI инвертирует создание зависимостей: объекты создаёт контейнер, а не сам класс
  • Регистрируйте службы с помощью AddTransient / AddScoped / AddSingleton
  • Внедрение через конструктор — стандартный и предпочтительный подход
  • Открытые обобщения, декораторы и ValidateOnBuild — мощные расширенные возможности

Часто задаваемые вопросы

Урок «Основы контейнера внедрения зависимостей» бесплатный?

Да — полный текст урока «Основы контейнера внедрения зависимостей» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс C# Academy, подпишись на CoddyKit PRO. Курс C# Academy содержит 4 уроков всего.

Чему я научусь в уроке «Основы контейнера внедрения зависимостей»?

Разберитесь в инверсии управления, регистрации служб и разрешении зависимостей контейнером внедрения зависимостей .NET. Ты практикуешь C# Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать C# Academy?

Предыдущий опыт не требуется. C# Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 1 из 4.

Сколько времени занимает урок «Основы контейнера внедрения зависимостей»?

Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.

Можно ли писать и запускать код в этом уроке C# Academy?

Да. Каждый урок C# Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Основы контейнера внедрения зависимостей
  2. Время жизни служб: Transient, Scoped, Singleton
  3. Внедрение через конструктор и интерфейсы
  4. Шаблоны фабрики и параметров
← Назад к C# Academy