Как зарегистрировать делегат или функцию в IServiceCollection, когда функция принадлежит классу, который должен быть разрешен? - PullRequest
2 голосов
/ 04 июня 2019

Я использую IServiceCollection / IServiceProvider из Microsoft.Extensions.DependencyInjection.

Я хочу внедрить делегат в класс:

public delegate ValidationResult ValidateAddressFunction(Address address);

public class OrderSubmitHandler
{
    private readonly ValidateAddressFunction _validateAddress;

    public OrderSubmitHandler(ValidateAddressFunction validateAddress)
    {
        _validateAddress = validateAddress;
    }

    public void SubmitOrder(Order order)
    {
        var addressValidation = _validateAddress(order.ShippingAddress);
        if(!addressValidation.IsValid)
            throw new Exception("Your address is invalid!");
    }
}

Реализация ValidateAddressFunction Я хочуИнъекция происходит из класса, который должен быть разрешен из контейнера, потому что у него есть собственные зависимости:

public class OrderValidator
{
    private readonly ISomeDependency _dependency;

    public OrderValidator(ISomeDependency dependency)
    {
        _dependency = dependency;
    }

    public ValidationResult ValidateAddress(Address address)
    {
        // use _dependency
        // validate the order
        // return a result
        return new ValidationResult();
    }
}

В этом примере я использую делегат, но я также мог бы вводить Func<Address, ValidationResult>.

Я мог бы просто ввести OrderValidator, но я бы не хотел создавать интерфейс только с одним методом.Если все мои потребности в классе - это один метод, я бы предпочел напрямую зависеть от этого.

Как зарегистрировать делегат или Func таким образом, чтобы при его разрешении класс, содержащий метод,быть решен, и тогда я могу использовать метод из разрешенного экземпляра?

1 Ответ

3 голосов
/ 04 июня 2019

Зарегистрируйте делегата или Func<Address, ValidationResult>, используя фабричный метод, который разрешает тип, который предоставляет метод, а затем возвращает метод.

В вашем примере вы захотите разрешить OrderValidator и вернуть его ValidateAddress метод.

// register the class that provides the method and its dependencies.
services.AddSingleton<OrderValidator>();
services.AddSingleton<ISomeDependency, SomeDependency>();

// register the delegate using a factory method that resolves 
// the type that provides the method and then returns the method.
services.AddSingleton<ValidateAddressFunction>(serviceProvider =>
{
    var validator = serviceProvider.GetRequiredService<OrderValidator>();
    return validator.ValidateAddress;
});

Это будет работать точно так же, если вы зарегистрируете Func<Address, ValidationResult> вместо делегата:

services.AddSingleton<Func<Address,ValidationResult>>(serviceProvider =>
{
    var validator = serviceProvider.GetRequiredService<OrderValidator>();
    return validator.ValidateAddress;
});

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

public static class ServiceCollectionDelegateExtensions
{
    public static IServiceCollection RegisterDelegateFromService<TService, TDelegate>(
        this IServiceCollection serviceCollection,
        Func<TService, TDelegate> getDelegateFromService)
        where TDelegate : class
    {
        return serviceCollection.AddTransient(serviceProvider =>
            getDelegateFromService(serviceProvider.GetRequiredService<TService>()));
    }
}

В этом случае делегат регистрируется с использованием AddTransient, поскольку время жизни класса действительно определяется при регистрации класса.

Теперь регистрация будет выглядеть так:

services.RegisterDelegateFromService<OrderValidator, ValidateAddressFunction>
    (validator => validator.ValidateAddress);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...