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

标签 c# dependency-injection autofac

我正在使用 Autofac。我想将一个委托(delegate)注入(inject)一个类:

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方法。

var builder = new ContainerBuilder();

// register the class that provides the method and its dependencies.

builder.RegisterType<OrderValidator>();
builder.RegisterType<SomeDependency>().As<ISomeDependency>();

// register the delegate using a factory method that resolves 
// the type that provides the method and then returns the method.

builder.Register<ValidateAddressFunction>(context =>
{
    var validator = context.Resolve<OrderValidator>();
    return validator.ValidateAddress;
});

如果您注册 Func<Address, ValidationResult>,这将以完全相同的方式工作而不是代表:

builder.Register<Func<Address, ValidationResult>>(context =>
{
    var validator = context.Resolve<OrderValidator>();
    return validator.ValidateAddress;
});

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

public static class AutofacDelegateExtensions
{
    public static IRegistrationBuilder<TDelegate, SimpleActivatorData, SingleRegistrationStyle> RegisterDelegateFromService<TService, TDelegate>(
        this ContainerBuilder builder,
        Func<TService, TDelegate> getDelegateFromService,
        string sourceComponentName = null)
        where TDelegate : class
    {
        var registrationFunction = new Func<IComponentContext, TDelegate>(context =>
        {
            var source = sourceComponentName == null
                ? context.Resolve<TService>()
                : context.ResolveNamed<TService>(sourceComponentName);
            return getDelegateFromService(source);
        });

        return builder.Register(registrationFunction);
    }
}

默认情况下,Autofac 注册是暂时的,因此提供委托(delegate)的类的生命周期由该类的注册决定。

现在注册看起来像这样:

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

或者,如果提供方法的依赖项 - 在本例中为 OrderValidator已注册名称,我们必须使用该名称解析它:

builder.RegisterDelegateFromService<OrderValidator, ValidateAddressFunction>(validator =>
    validator.ValidateAddress, "RegistrationName");

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

相关文章:

c# - 如何最好地用C#4编写自己的后台工作和可交流的(发送进度更新并获取消息)非可视类?

c# - .Net StreamWriter.BaseStream,这个定义是什么意思? "Gets the underlying stream that interfaces with a backing store."

dependency-injection - 我的工厂对象是否引入了全局状态?

c# - “不支持返回 System.IServiceProvider 的 ConfigureServices。”

c# - 如何在 Windows 10 和 > .net 4.5 中用 c# 枚举音频输入设备?

c# - 升级到 3.1 后,ASP.NET Core 未绑定(bind)正文中的参数

java - 如何使用 Dagger2 在其构造函数中注入(inject)带有参数的对象

swift - 尝试使用依赖倒置存储值时崩溃

Autofac - 一个接口(interface),多种实现

c# - Automapper 和 Autofac