gpt4 book ai didi

c# - 配置 Unity 以解析采用修饰依赖项的类型,该依赖项的参数随注入(inject)的类型而变化

转载 作者:可可西里 更新时间:2023-11-01 08:26:31 26 4
gpt4 key购买 nike

这是一个相当直接的装饰器模式场景,复杂的是装饰类型有一个构造函数参数,该参数取决于它被注入(inject)的类型。

我有一个这样的界面:

interface IThing
{
void Do();
}

像这样的实现:

class RealThing : IThing
{
public RealThing(string configuration)
{
... implementation ...
}

public void Do()
{
... implementation ...
}
}

还有这样的装饰器:

class DecoratingThing : IThing
{
IThing _innerThing;

public DecoratingThing(IThing thing)
{
_innerThing = thing;
}

public void Do()
{
_innerThing.Do();
}
}

最后,我有一些类型需要 IThing , 称为 Depender1 , Depender2等..

class DependerX()
{
public DependerX(IThing thing)
{
... implementation ...
}
}

我想配置一个 IOC 容器来解析 DependerX 的实例这样他们就会被注入(inject) RealThingDecoratingThing 装饰. 重要:每个DependerX type 需要不同的值 configuration传递给其 RealThing 的构造函数, 在每种情况下都说“ConfigX”。例如IoC 容器完成的工作可能是:

new Depender1(new DecoratingThing(new RealThing("Config1")));
new Depender2(new DecoratingThing(new RealThing("Config2")));

...等等。

在 Unity 中,这似乎很难配置,因为我必须将装饰器与装饰器混合使用:

container.RegisterType<IThing, DecoratingThing>("ConfigX",
new InjectionFactory(container => new DecoratingThing(new RealThing("ConfigX"));

container.RegisterType<DependerX>(
new InjectionConstructor(new ResolvedParameter<IThing>("ConfigX");

然后重复,很好地违反 DRY,对于每个 DependerX .

我想做的是消除嵌入 RealThing 结构的需要在建DecoratingThingIThing 的每个命名注册中- 只声明装饰一次。例如,如果将来需要更 retrofit 饰,则重新配置会更容易。我想到的最好的方法是这个注册辅助方法:

void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(new RealThing(config))));
}

这至少消除了重复,但我仍然必须嵌入 RealThing 的结构在DecoratingThing里面- 这意味着我不能独立地改变他们的生命周期。我无法注册 IThing再次这样做是因为我已经用完了该接口(interface)的名称注册。如果我想这样做,我必须像这样引入另一组命名实例:

void RegisterDepender<TDepender>(IUnityContainer container, string config)
{
string realConfig = "Real" + config;

container.RegisterType<TDepender>(new InjectionConstructor(
new ResolvedParameter<IThing>(config)));
container.RegisterType<IThing, DecoratingThing>(config,
new InjectionFactory(c => new DecoratingThing(
container.Resolve<IThing>(realConfig))));
container.RegisterType<IThing, RealThing>(realConfig,
new ContainerControlledLifetimeManager(),
new InjectionConstructor(config));
}

真的是最好的选择吗?对于那些想要理解的人来说,这感觉很复杂,而且可能很难。其他 IoC 容器是否有令人信服的方式来涵盖这种情况?由于每个 DependerX 的注入(inject)工作模式都是重复的,有没有办法只在顶层 ( DependerX ) 级别使用命名实例?

还有其他意见吗?

最佳答案

类设计本身似乎是合理的。下面是一个基于约定的容器配置,基本上是这样做的:

public class MyConventions : UnityContainerExtension
{
protected override void Initialize()
{
var dependers = from t in typeof(IThing).Assembly.GetExportedTypes()
where t.Name.StartsWith("Depender")
select t;

foreach (var t in dependers)
{
var number = t.Name.TrimStart("Depender".ToArray());
var realName = "Real" + number;
var decoName = "Deco" + number;
var config = "Config" + number;
this.Container.RegisterType<IThing, RealThing>(realName,
new InjectionConstructor(config));
this.Container.RegisterType<IThing, DecoratingThing>(decoName,
new InjectionConstructor(
new ResolvedParameter<IThing>(realName)));
this.Container.RegisterType(t,
new InjectionConstructor(
new ResolvedParameter<IThing>(decoName)));
}
}
}

这个配置会自动添加所有匹配上述谓词的类,所以一旦你设置好了,你可以添加更多的类(比如 Depender4Depender5 ) 而无需重新访问容器配置。

以上配置满足这些单元测试:

[Fact]
public void ContainerCorrectlyResolvesDepender1()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender1>();

var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config1", thing.Configuration);
}

[Fact]
public void ContainerCorrectlyResolvesDepender2()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender2>();

var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config2", thing.Configuration);
}

[Fact]
public void ContainerCorrectlyResolvesDepender3()
{
var container = new UnityContainer().AddNewExtension<MyConventions>();
var actual = container.Resolve<Depender3>();

var deco = Assert.IsAssignableFrom<DecoratingThing>(actual.Thing);
var thing = Assert.IsAssignableFrom<RealThing>(deco.Thing);
Assert.Equal("Config3", thing.Configuration);
}

关于c# - 配置 Unity 以解析采用修饰依赖项的类型,该依赖项的参数随注入(inject)的类型而变化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9004297/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com