Основы контейнера внедрения зависимостей
Разберитесь в инверсии управления, регистрации служб и разрешении зависимостей контейнером внедрения зависимостей .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 — локальная установка не требуется.
Все уроки этого курса
- Основы контейнера внедрения зависимостей
- Время жизни служб: Transient, Scoped, Singleton
- Внедрение через конструктор и интерфейсы
- Шаблоны фабрики и параметров