C# 如何从外向内将装饰程序与Ninject绑定?
我将ninject绑定与C# 如何从外向内将装饰程序与Ninject绑定?,c#,dependency-injection,ninject,decorator,C#,Dependency Injection,Ninject,Decorator,我将ninject绑定与一起使用,当ninjectedTo从内到外绑定装饰器时。但是,从不同的入口点,我需要不同的功能,可能以不同的顺序运行,所以我想从外向内绑定decorators链。Ninject可以这样做吗 我将活着实现这一目标: Bind<IFooService>().To<SimpleService>().WhenInjectedInto<FeatureAFooServiceDecorator>(); Bind<IFooService>(
一起使用,当ninjectedTo
从内到外绑定装饰器时。但是,从不同的入口点,我需要不同的功能,可能以不同的顺序运行,所以我想从外向内绑定decorators链。Ninject可以这样做吗
我将活着实现这一目标:
Bind<IFooService>().To<SimpleService>().WhenInjectedInto<FeatureAFooServiceDecorator>();
Bind<IFooService>().To<FeatureAFooServiceDecorator>().WhenInjectedInto<FeatureBFooServiceDecorator>();
Bind<IFooService>().To<FeatureBFooServiceDecorator>().WhenInjectedInto<EntryPoint1>();
Bind<IFooService>().To<SimpleService>().WhenInjectedInto<FeatureBFooServiceDecorator>();
Bind<IFooService>().To<FeatureBFooServiceDecorator>().WhenInjectedInto<EntryPoint2>();
编辑:
要手动实现这一点,我将执行以下操作:
var entryPoint1 = new EntryPoint1(new FeatureBFooServiceDecorator(new FeatureAFooServiceDecorator(new SimpleService)));
var entryPoint2 = new EntryPoint2(new FeatureBFooServiceDecorator(new SimpleService));
(当然,我会避免更新内容,因为这些类每个都有两个以上的依赖项,其中一些是requestscope中的InRequestScope
或namedscope中的InNamedScope
)
注意:对于上面的示例,请说明有以下类别:
public interface IFooService {/*...*/}
public class SimpleService : IFooService {/*...*/}
public class FeatureAFooServiceDecorator : IFooService
{
private readonly IFooService _innerFooService;
public FeatureAFooServiceDecorator(IFooService fooService) {
_innerFooService = fooService;
}
}
public class FeatureBFooServiceDecorator : IFooService {/*...same as above...*/}
public class EntryPoint1{
public EntryPoint1(IFooService fooService){/*...*/}
}
public class EntryPoint2{
public EntryPoint2(IFooService fooService){/*...*/}
}
所以我想你想做的是
public class FeatureBFooService : IFooService
{
public FeatureBFooService(IFooService service1, IFooService service2)
{ ...}
}
var service = new FeatureBFooService(new FeatureAFooService(), new SimpleService());
(当然,你不想自己做新的)。因此,您多次使用同一接口,即使是针对同一个构造函数,但您不仅需要不同的实例,还需要将不同的类型(FeatureAFooService
,SimpleService
)注入到FeatureBFooService
的构造函数中
我有两种方法可以考虑如何实现这一目标。
但老实说,我应该警告你,这似乎很复杂。通常这意味着设计并不理想,你最好考虑如何以不同的方式解决问题。毕竟,当实现共享同一个接口时,它们不应该做同样的事情吗?将IFooService
的集合注入到使用所有这些服务的类中是一回事,但该类本身也是IFooService
似乎有点奇怪。
但说得够多了,我相信人们会做出自己的选择——有时会犯错——因为这是最好的学习方式。当然,我的假设也可能是错误的,你所追求的是最好的解决方案
解决方案1:.ToConstructor()
绑定
Bind<IFooService>().ToConstructor(ctorArg => new FeatureBFooService(ctorArg.Inject<FeatureAFooService>(), ctorArg.Inject<SimpleService>()));
其中,FooServiceProvider
将根据您的自定义逻辑决定要实例化的确切依赖项。那么,它也可以这样做
IResolutionRoot.Get<FeatureAFooService>();
例如,它可能看起来像(伪代码):
公共类FooServiceProvider:提供程序
{
受保护的覆盖IFooService CreateInstance(IContext上下文)
{
类型returnType=确定实现类型(上下文);
开关(返回式)
{
案例类型(功能增强服务):
返回CreateFeaturebFoosService(上下文);
中断:
违约:
抛出新的NotSupportedException(…);
}
}
私有静态类型determineImplementType(IContext上下文)
{
//这里是您的自定义逻辑
}
私有静态IFooService CreateFeatureBFooService(IContext上下文)
{
var dependency1=context.Kernel.Get(FeatureAFooService);
var dependency2=context.Kernel.Get(SimpleService);
返回context.Kernel.Get(
功能增强服务,
新的构造论证(“服务1”,从属关系1),
新的构造论证(“服务2”,从属关系2));
}
}
请注意,对于ConstructorArgument
,值被注入到与名称匹配的构造函数参数中(service1
,service2
),因此这是一个重构陷阱。
还要注意,如果需要保留上下文,也可以使用IContext.Kernel.ContextPreservingGet
。但是,这仅适用于扩展名ninject.extensions.ContextPreservation。你能举个例子吗?@Steven当然,请参阅我的编辑你能更新你的代码吗?你能用没有ninject的手动连接方式来更新代码吗,也就是用一堆新的
语句吗?
public const string FeatureAService = "FeatureA";
public const string SimpleService = "Simple";
public class FeatureBFooService : IFooService
{
public FeatureBFooService(
[Named(FeatureAService)]I FooService service1,
[Named(SimpleService] IFooService service2)
{ ...}
}
Bind<IFooService>().To<FeatureAService>().Named(FeatureAService);
Bind<IFooService>().To<SimpleService>().Named(SimpleService);
Bind<IFooService>().ToProvider<FooServiceProvider>();
IResolutionRoot.Get<FeatureAFooService>();
IResolutionRoot.Get<IFooService>(FeatureAService);
public class FooServiceProvider : Provider<IFooService>
{
protected override IFooService CreateInstance(IContext context)
{
Type returnType = DetermineImplementationType(context);
switch(returnType)
{
case typeof(FeatureBFooService):
return CreateFeatureBFooService(context);
break:
default:
throw new NotSupportedException(...);
}
}
private static Type DetermineImplementationType(IContext context)
{
// your custom logic here
}
private static IFooService CreateFeatureBFooService(IContext context)
{
var dependency1 = context.Kernel.Get<IFooService>(FeatureAFooService);
var dependency2 = context.Kernel.Get<IFooService>(SimpleService);
return context.Kernel.Get<IFooService>(
FeatureBFooService,
new ConstructorArgument("service1", dependency1),
new ConstructorArgument("service2", dependency2));
}
}