如何通过带有条件装饰器的委托工厂解析服务?

时间:2017-07-31 13:49:03

标签: c# autofac

我有一个班级雇佣队伍,看起来像这样:

public class Foo : IFoo
{
    private readonly IBar _bar;

    public Foo(IBar bar)
        => _bar = bar;
}

public class Bar : IBar
{
    private readonly Func<IFoo> _fooFunc;
    private readonly IBaz _baz;

    public Bar(Func<IFoo> fooFunc, IBaz baz)
    {
         _fooFunc = fooFunc;
         _baz = baz;
    }
}

public class Baz : IBaz
{
}

public class BazDecorator : IBaz
{
    private readonly IBaz _decoratee;

    public BarDecorator(IBaz decoratee)
        => _decoratee = decoratee;
}

请注意Bar直接使用Func<IFoo>代替IFoo,因为解析IFoo时存在循环依赖关系。

我目前的注册看起来像这样:

public class MyModule : Module
{
    protected override void Load(ContainerBuilder builder)
    {
        builder.RegisterType<Foo>().As<IFoo>();

        builder.RegisterType<Bar>().As<IBar>();

        // Func<IFoo> is automatically resolved in AutoFac

        builder.RegisterType<Baz>().Named<IBaz>("baz");

        builder.RegisterDecorator<IBaz>((c, inner) =>
            new BazDecorator(inner),
            fromKey: "baz");
    }
}

我希望仅在通过BazDecorator 而不是 Foo解析时有条件地注册Func<IFoo>,如下:

Foo------Bar-----BazDecorator----Baz
          \
           \
            \____Foo----Bar----Baz

如何在AutoFac中注册我的服务?

1 个答案:

答案 0 :(得分:2)

您需要手动注册Func<IFoo>,以便将明确的参数明确传递给FooBar组件

builder.Register<Func<IFoo>>(c =>
    {
        var ctx = c.Resolve<IComponentContext>();
        return () => new Foo(new Bar(() => ctx.Resolve<IFoo>(), ctx.ResolveNamed<IBaz>("baz")));
    });

如果您不想在Foo函数中使用“new”BarRegister,也可以通过从容器中解析它们来实现,但代码看起来非常讨厌:

builder.Register<Func<IFoo>>(c =>
    {
        var ctx = c.Resolve<IComponentContext>();
        return () => ctx.Resolve<IFoo>(
            new ResolvedParameter(
                (p, cx) => p.Name == "bar", 
                (p, cx) => cx.Resolve<IBar>(new ResolvedParameter(
                    (p1, c1) => p1.Name == "baz", 
                    (p1, c1) => c1.ResolveNamed<IBaz>("baz")))));
    });