如何在 Castle Windsor 的依赖图中进一步指定服务覆盖?
How to specify a service override further down the dependency graph in Castle Windsor?
这是我的场景的简化。
我有一些接口 IFoo
、IBar
和 IBaz
及其实现 Foo
、Bar
和 Baz
。
Foo
依赖于 IBar
而 Bar
依赖于 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;
}
}
}}
这是我的场景的简化。
我有一些接口 IFoo
、IBar
和 IBaz
及其实现 Foo
、Bar
和 Baz
。
Foo
依赖于 IBar
而 Bar
依赖于 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;
}
}
}}