问题 在autofac中注册装饰器而无需手动指定所有依赖项


我有一个装饰器,有一些其他依赖项,也应该使用容器解决。 例:

public class FooDecorator : IFoo
{
    public FooDecorator(IFoo inner, IBar bar, IBaz baz)
}

我可以这样注册:

builder.RegisterType<Foo>().As<IFoo>();
builder.RegisterDecorator<IFoo>((c, inner) => 
    new FooDecorator(inner, c.Resolve<IBar>(), c.Resolve<IBaz>()), "key");

这是有效的,但不是很好,我必须手动指定所有其他依赖项。我想做的是:

builder.RegisterDecorator<FooDecorator, IFoo>("key");

在哪里 IFoo 被解决了'内在' IFoo 并从容器中解析其他依赖项。这是可能的,还是我可以用Func注册装饰器,这将导致这种行为?


9210
2018-06-20 09:43


起源



答案:


为了避免手动指定所有依赖项,您应该在中注册装饰器 Autofac 并在第一个参数内解析它 RegisterDecorator 方法。

builder.RegisterType<Foo>()
       .Named<IFoo>("original");
builder.RegisterType<FooDecorator>()
       .Named<IFoo>("decorator");
builder.RegisterDecorator<IFoo>((c, inner) => c.ResolveNamed<IFoo>("decorator", TypedParameter.From(inner)), "original")
       .As<IFoo>();

使用命名注册注册装饰器将避免任何冲突。


11
2018-06-19 10:22



这很棒,但是如果你不知道(或关心)具体实现的话 IFoo 是 Foo?是否有可能按照“装饰当前正在解决的任何内容”的方式声明某些内容 IFoo 同 FooDecorator“?(假设IFoo之前​​已注册提供 IFoo,但不一定是 命名 服务) - PS我认为这也是OP所期待的 - Cristi Diaconescu
@CristiDiaconescu没有简单的解决方案来执行此操作,如果没有为第一个装饰器指定命名,您将在Autofac容器中进行2次注册。如果您想了解如何实现您想要的更多细节,请随意提出新问题。 - Cyril Durand


答案:


为了避免手动指定所有依赖项,您应该在中注册装饰器 Autofac 并在第一个参数内解析它 RegisterDecorator 方法。

builder.RegisterType<Foo>()
       .Named<IFoo>("original");
builder.RegisterType<FooDecorator>()
       .Named<IFoo>("decorator");
builder.RegisterDecorator<IFoo>((c, inner) => c.ResolveNamed<IFoo>("decorator", TypedParameter.From(inner)), "original")
       .As<IFoo>();

使用命名注册注册装饰器将避免任何冲突。


11
2018-06-19 10:22



这很棒,但是如果你不知道(或关心)具体实现的话 IFoo 是 Foo?是否有可能按照“装饰当前正在解决的任何内容”的方式声明某些内容 IFoo 同 FooDecorator“?(假设IFoo之前​​已注册提供 IFoo,但不一定是 命名 服务) - PS我认为这也是OP所期待的 - Cristi Diaconescu
@CristiDiaconescu没有简单的解决方案来执行此操作,如果没有为第一个装饰器指定命名,您将在Autofac容器中进行2次注册。如果您想了解如何实现您想要的更多细节,请随意提出新问题。 - Cyril Durand


根据Cyril Durand的回答,这里是注册装饰器的通用辅助方法:

    private void RegisterDecorator<TInterface, TImplementation, TDecorator>(ContainerBuilder builder) where TImplementation : TInterface where TDecorator : TInterface
    {
        builder.RegisterType<TImplementation>().Named<TInterface>("implementation");
        builder.RegisterType<TDecorator>().Named<TInterface>("decorator");
        builder.RegisterDecorator<TInterface>((c, inner) => c.ResolveNamed<TInterface>("decorator", TypedParameter.From(inner)), "implementation");
    }

如果需要多个嵌套装饰器,可以引入具有更多通用参数(TDecorator1,TDecorator2等)的类似方法。


3
2017-12-29 11:12