C# 如何从外向内将装饰程序与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>(

我将ninject绑定与
一起使用,当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));
    }
}