Внедрение зависимостей в .NET MAUI. Методы регистрации зависимостей

Как мы уже знаем, методы регистрации зависимостей имеют название, соответствующее шаблону Add[Lifecycle]() или AddKeyed[Lifecycle](). При этом, каждый из методов имеет ряд переопределенных версий. В этой части мы рассмотрим различные методы регистрации сервисов и их применение в приложениях .NET MAUI.

Методы регистрации сервисов

Стоит отметить, что методы расширения для регистрации сервисов, вне зависимости от жизненного цикла сервиса, имеют схожие параметры. Поэтому нет смысла дублировать информацию о том или ином методе регистрации несколько раз только исходя из того, что меняется жизненный цикл сервиса. Ниже мы рассмотрим все методы только для transient-сервисов. Методы расширения IServiceCollection для регистрации transient-сервисов в .NET 9 выглядят следующим образом:

  Метод Параметры метода
1
public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType);
  • serviceType— тип сервиса и его реализации
2
public static IServiceCollection AddTransient<TService>(this IServiceCollection services) where TService : class;
Универсальная версия предыдущего метода.

  • TService — тип сервиса и его реализация
3
public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Func<IServiceProvider,object> implementationFactory);
  • serviceType — тип сервиса
  • implementationFactory — фабрика для создания экземпляров сервиса
4
public static IServiceCollection AddTransient<TService>(this IServiceCollection services, Func<IServiceProvider,TService> implementationFactory) where TService : class;
Универсальная версия предыдущего метода:

  • TService — тип сервиса
  • implementationFactory — фабрика для создания экземпляров сервиса
5
public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Type implementationType);
  • serviceType — тип сервиса
  • implementationType — тип реализации сервиса
6
public static IServiceCollection AddTransient<TService,TImplementation>(this IServiceCollection services) where TService : class where TImplementation : class, TService;
Универсальная версия предыдущего метода

  • TService — тип сервиса
  • TImplementation — тип реализации сервиса
7
public static IServiceCollection AddTransient<TService,TImplementation>(this IServiceCollection services, Func<IServiceProvider,TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;
  • TService — тип сервиса
  • TImplementation — тип реализации сервиса
  • implementationFactory — фабрика для создания экземпляров сервиса

Также можно использовать семь версий методов вида AddKeyedTransient(). Отличие этих методов от представленных выше заключается только в наличие ещё одного параметра — serviceKey типа object — ключа сервиса. Сервисы с ключами и их применение мы рассмотрим чуть позже, а пока остановимся на обычных сервисах. Каждый из этих методов может оказаться удобным в определенных случаях.

Первые две версии метода:

public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType);
public static IServiceCollection AddTransient<TService>(this IServiceCollection services) where TService : class;

удобно использовать в том случае, когда сервис имеет всего одну реализацию. Например, сейчас наш сервис ILogger имеет всего одну реализацию — класс FileLogger. И, если не предполагается, что у сервиса могут появиться когда-либо другие реализации, то, в этом случае, нет никакой необходимости создавать отдельный сервис и, затем, реализовывать его в классе. Можно просто зарегистрировать в качестве сервиса конкретный класс:

builder.Services.AddTransient(typeof(FileLogger)); //первый вариант
builder.Services.AddTransient<FileLogger>();//второй вариант

Версии метода с использованием фабрики:

public static IServiceCollection AddTransient(this IServiceCollection services, Type serviceType, Func<IServiceProvider,object> implementationFactory);
public static IServiceCollection AddTransient<TService>(this IServiceCollection services, Func<IServiceProvider,TService> implementationFactory) where TService : class;

Использование фабрики при регистрации сервиса может оказаться удобной в случае, если вам требуется более сложная логика создания объекта сервиса, чем обычный вызов конструктора класса. Например, мы захотим передать в сервис дополнительную информацию, через его свойство:

public class FileLogger: ILogger
{
    const string FILE_NAME = "Log.txt";
    private readonly DateTime _currentTime;

    private string fileName;

    public string FileName {
        get { 
               return fileName; 
        }
        set { 
            fileName = value; 
        } 
    }
   
    private readonly string _newLine = Environment.NewLine;

    public FileLogger()
    {
        _currentTime = DateTime.Now;
        fileName = FILE_NAME;
    }

    public void WriteLine(string message)
    {
        File.AppendAllText(fileName, $"[{_currentTime}] - {message}{_newLine}");
    }
}

Один из вариантов это сделать — воспользоваться методом с фабрикой:

builder.Services.AddTransient(typeof(ILogger), (provider) => 
{
    return new FileLogger()
    {
        FileName = "Log.txt"
    };
});
//ИЛИ ТАК
builder.Services.AddTransient<FileLogger>((provider) => 
{
    return new FileLogger() 
    {
        FileName = "Log.txt"
    };

});

Следующие две версии метода применяются в том случае, если наш сервис предполагает множество реализаций. В этом случае мы указываем в параметрах тип сервиса (интерфейс) и его конкретную реализацию, которая будет использоваться в приложении:

builder.Services.AddTransient(typeof(ILogger), typeof(FileLogger));
//ИЛИ
builder.Services.AddTransient<ILogger, FileLogger>();

И, наконец, последняя версия метода

public static IServiceCollection AddTransient<TService,TImplementation>(this IServiceCollection services, Func<IServiceProvider,TImplementation> implementationFactory) where TService : class where TImplementation : class, TService;

совмещает в себе все преимущества — здесь мы можем не только использовать сервис и его реализацию, но и применить фабрику при создании объекта сервиса:

builder.Services.AddTransient<ILogger, FileLogger>((provider) => 
{
    return new FileLogger()
    {
        FileName = "Log.txt"
    };
});

Итого

Выше мы рассмотрели методы регистрации сервисов с жизненным циклом transient (временный). Аналогичные методы используются и для сервисов с другим жизненным циклом. Выбор того или иного метода регистрации зависит от конкретной ситуации — имеет ли сервис множество реализаций или только одну, требуется ли сложна логика создания реализации сервиса или нет и так далее.

Подписаться
Уведомить о
guest
0 Комментарий
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии