如何在 Castle Windsor 的依赖图中进一步指定服务覆盖?

How to specify a service override further down the dependency graph in Castle Windsor?

这是我的场景的简化。

我有一些接口 IFooIBarIBaz 及其实现 FooBarBaz

Foo 依赖于 IBarBar 依赖于 IBaz,因此依赖关系图如下所示:

   Foo 
    |
   Bar
    |
   Baz

我的 Windsor 配置如下所示,一切正常:

container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
container.Register(Component.For<IBar>().ImplementedBy<Bar>());
container.Register(Component.For<IBaz>().ImplementedBy<Baz>());

现在我需要引入一个新的 SpecialBaz,当我的依赖关系图以 Foo 开头时,我想使用它来代替旧的 Baz。应用程序的其余部分将继续使用旧版 Baz:

      Foo           SomethingElse
       |                  |
      Bar                Bar
       |                  |
   SpecialBaz            Baz

我尝试将 SpecialBaz 命名为 ServiceOverride api:

container.Register(Component.For<IBaz>().ImplementedBy<Baz>().IsDefault());
container.Register(Component.For<IBaz>().Named("special baz").ImplementedBy<SpecialBaz>());

container.Register(Component.For<IFoo>()
                            .ImplementedBy<Foo>()
                            .DependsOn(ServiceOverride.ForKey<IBaz>().Eq("special baz")));

并指定依赖关系:

container.Register(Component.For<IBaz>().ImplementedBy<Baz>().IsDefault());
container.Register(Component.For<IBaz>().ImplementedBy<SpecialBaz>());

container.Register(Component.For<IFoo>()
                            .ImplementedBy<Foo>()
                            .DependsOn(Component.For<IBaz>().ImplementedBy<SpecialBaz>()));

但这两种方法都不起作用。

这在 Castle Windsor 中可行吗?我该如何连接它?

简短答案是 - 温莎城堡可以。每个 DI 容器都可以。我会给你一个规则来记住你可以解决你的大部分依赖问题。

答案。

规则:每个间接点都需要一个抽象层。当您尝试在应用程序中构建依赖项解决方案时,请牢记此规则。据我所知有两种间接方式 - 静态和动态。

您需要在一个点更改图形,并且仅更改一次间接)但是不知何故,您需要在运行时遍历依赖关系图,以查看是否为 Foo 请求了 Baz。所以你需要某种工厂(抽象事物)。

你有两个选项,具体取决于一个问题的答案:

我的更改取决于静态还是动态条件?

例如 - 如果您依赖于传入的用户数据或环境数据 - 您处于动态情况下,您需要使用 Dynamic Parameters 或其他功能。

在你的情况下,你的依赖是静态的。

and I want to use it instead of the old Baz when my dependency graph begins with a Foo.

一旦图表的开头是 Foo,特殊 Baz 的条件就永远不会改变。

您可以使用工厂方法或类型化工厂组件选择器来实现。我为您提供了工厂方法的示例:

using System;
using Castle.MicroKernel.Registration;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            var container = new Castle.Windsor.WindsorContainer();
            container.Register(Component.For<IFoo>().ImplementedBy<Foo>());
            container.Register(Component.For<ISomethingElse>().ImplementedBy<SomethingElse>());

            container.Register(Component.For<IBar>().ImplementedBy<Bar>().LifeStyle.Transient);

            container.Register
            (
                Component
                .For<IBaz>()
                .UsingFactoryMethod
                (
                    (k, c) =>
                    {
                        IBaz resolved = null;
                        var requestingType = c.Handler.ComponentModel.Implementation;
                        if (requestingType == typeof(Foo))
                        {
                            resolved = new Baz();
                        }
                        else
                        {
                            resolved = new BazSpecial();
                        }

                        return resolved;
                    }
                ).LifeStyle.Transient
            );

            var f = container.Resolve<IFoo>();
            var se = container.Resolve<ISomethingElse>();

            Console.ReadLine();
        }
    }
    internal interface IBar
    {
    }

    internal interface IBaz
    {
    }

    internal interface IFoo
    {
    }

    interface ISomethingElse
    {

    }


    internal class Bar : IBar
    {
        private readonly IBaz baz;

        public Bar(IBaz baz)
        {
            this.baz = baz;
        }

    }

    internal class Baz : IBaz
    {
    }

    internal class BazSpecial : IBaz
    {
    }

    internal class Foo : IFoo
    {
        private readonly IBar bar;

        public Foo(IBar bar)
        {
            this.bar = bar;
        }
    }

    internal class SomethingElse : ISomethingElse
    {
        private readonly IBar bar;

        public SomethingElse(IBar bar)
        {


         this.bar = bar;
        }
    }
}}