c# - 当函数属于必须解析的类时,如何向 IServiceCollection 注册委托(delegate)或函数?

标签 c# .net dependency-injection

我正在使用来自 Microsoft.Extensions.DependencyInjection 的 IServiceCollection/IServiceProvider。

我想向类中注入(inject)一个委托(delegate):

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我想注入(inject)来自一个必须从容器中解析的类,因为它有自己的依赖关系:

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();
    }
}

在这个例子中,我使用了一个委托(delegate),但我也可以注入(inject) Func<Address, ValidationResult> .

我可以注入(inject) OrderValidator ,但我不想只用一种方法创建接口(interface)。如果我的类(class)只需要一种方法,那么我宁愿直接依赖它。

如何注册委托(delegate)或 Func以这样一种方式,当它被解析时,包含该方法的类将被解析,然后我可以使用已解析实例中的方法?

最佳答案

注册代表或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;
});

您可以使用扩展程序简化注册。它并没有那么短,但如果您可能有多个这样的注册,它仍然有帮助。它也可能有助于表达您的意图,因此很明显您正在注册要注入(inject)的委托(delegate)而不是类实例或接口(interface)实现:

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

在这种情况下,代理是使用 AddTransient 注册的因为类的生命周期是在类注册时真正确定的。

现在注册看起来像这样:

services.RegisterDelegateFromService<OrderValidator, ValidateAddressFunction>
    (validator => validator.ValidateAddress);

关于c# - 当函数属于必须解析的类时,如何向 IServiceCollection 注册委托(delegate)或函数?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56447219/

相关文章:

c# - 使用 XML 序列化时的循环引用?

c# - 编程 SaaS 应用程序

c# - 来自 Windows Store 应用程序的 Windows Azure 存储 REST API 的授权 header

c# - 一次在十个图片框上显示多张图片

.net - 如何在 .NET 中通过管道传输 stdout/stderr?

java - 使用 Guice 创建同一个类的多个实例

dependency-injection - Ninject - 如何以及何时注入(inject)

c# - 属性引起的 Stackoverflow 异常

.net - 从哪里可以获得更多 VS2010 主题?

c#-4.0 - 无法获取 Integration 类 ninject 的默认构造函数