C# 配置Unity以解析接受修饰依赖项的类型,该依赖项具有随注入类型而变化的参数
这是一个相当直截了当的装饰器模式场景,复杂的是装饰类型有一个构造函数参数,该参数依赖于它被注入的类型 我有这样一个界面:C# 配置Unity以解析接受修饰依赖项的类型,该依赖项具有随注入类型而变化的参数,c#,dependency-injection,inversion-of-control,unity-container,ioc-container,C#,Dependency Injection,Inversion Of Control,Unity Container,Ioc Container,这是一个相当直截了当的装饰器模式场景,复杂的是装饰类型有一个构造函数参数,该参数依赖于它被注入的类型 我有这样一个界面: interface IThing { void Do(); } class RealThing : IThing { public RealThing(string configuration) { ... implementation ... } public void Do() { ...
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();
}
}
以及这样的实现:
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();
}
}
还有像这样的装饰师:
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
的实例,以便它们被注入RealThing
,并用decormingthing
装饰重要提示:每个DependerX
类型都要求将不同的配置值
传递给其实体的构造函数
,在每种情况下都说“ConfigX”。e、 g.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");
这至少消除了重复,但我仍然必须将RealThing
的构造嵌入DecoratingThing
——这意味着我不能独立地改变它们的生命周期。我无法再次注册以执行此操作,因为我已用光了该接口的名称注册。如果我想这样做,我必须引入另一组命名实例,如下所示:
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));
}
void RegisterDepender(IUnityContainer容器,字符串配置)
{
字符串realConfig=“Real”+config;
container.RegisterType(新注入构造函数)(
新的解析参数(配置));
container.RegisterType(配置,
新注入工厂(c=>新装饰(
container.Resolve(realConfig));
container.RegisterType(realConfig,
新建ContainerControlled LifetimeManager(),
新的InjectionConstructor(config));
}
这真的是最好的选择吗?这让人觉得很复杂,而且对于那些后来的人来说,可能很难去摸索。其他IoC容器是否有一种引人注目的方式来涵盖这种情况?由于注入如何工作的模式对每个DependerX都是重复的,因此有没有办法只在顶部(DependerX
)级别使用命名实例
还有其他意见吗?你有没有想过让你的装饰程序基于Unity拦截功能?然后,只需使用这个拦截器一次,就可以很容易地说“截获对的调用”
container.AddNewExtension<Interception>();
container.RegisterType<IThing>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<DecoratingThingBehavior>());
班级设计本身似乎是合理的。下面是一个基于约定的容器配置,基本上可以做到这一点:
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)));
}
}
}
我认为这是一种不同的装饰方法,而不是它的实现。我已经考虑过了,我认为在这个特殊的案例中,我并没有真正处理一个合适的交叉关注点。它的范围非常具体,并且装饰器的行为取决于所调用的方法。我认为在这种情况下,我可能会将复杂性转换为拦截的逻辑。我拥有的装饰器是预先存在的,非常复杂,并且在其他地方使用,所以重构是非常重要的。考虑到问题中的信息,这是一个很好的建议,所以我给它加1分。谢谢。我认为在我的特定场景中,基于约定的方法是可行的。这并不是说其他方法(如上面的拦截思想)并不同样有效。很高兴听到我在这里还没有偏离常规!