C# 当注入任何条件时与绑定

C# 当注入任何条件时与绑定,c#,ninject,C#,Ninject,我有一个服务接口 interface IService { } 以及一些实现 class ServiceA : IService { } class ServiceB : IService { } class ServiceDefault : IService { } 我的课程使用iSeries设备,比如 class ServiceUse { public ServiceUse(IService svc) { } } 应根据上下文状态将一个IService实现注入到消费类中 为了实

我有一个服务接口

interface IService { }
以及一些实现

class ServiceA : IService { }
class ServiceB : IService { }
class ServiceDefault : IService { }
我的课程使用iSeries设备,比如

class ServiceUse
{
    public ServiceUse(IService svc) { }
}
应根据上下文状态将一个
IService
实现注入到消费类中

为了实现这一点,我有
ServiceProvider

static class ServiceNames
{
    public const string ServiceA = "ServiceA";
    public const string ServiceB = "ServiceB";
    public const string ServiceDefault = "ServiceDefault";
}

class ServiceProvider : Provider<IService>
{
    protected override IService CreateInstance(IContext context)
    {
        ServiceKindEnum kind = GetServiceKind(HttpContext.Current);
        string bindingName = $"Service{kind}";

        if (context.Kernel.CanResolve<IService>(bindingName))
            return context.Kernel.Get<IService>(bindingName);

        return context.Kernel.Get<IService>(ServiceNames.ServiceDefault);
    }
    ...
}
我必须将其类型添加为指向
ServiceProvider

Bind<IService>().ToProvider<ServiceProvider>()
    .WhenInjectedInto(typeof(ServiceUse), typeof(AnotherServiceUse));

选项是什么?

正如您当前问题中的代码现在看起来一样,您有两个用于解决
iSeries设备的用例:

  • 您正在请求一个命名绑定-有几个服务,包括一个命名的“默认服务”
  • 您正在请求一个未命名的绑定,该绑定总是通过同一个绑定(与提供程序的绑定)进行解析,该绑定还受到
    的约束(当被导入时)
如果您的示例实际上是完整的,那么整个
whenInjectedTo
可以通过一个条件大大简化,该条件声明不应该对请求进行约束。因此,您的绑定应该如下所示:

Bind<IService>().To<ServiceA>()
    .Named(ServiceNames.ServiceA);
Bind<IService>().To<ServiceB>()
    .Named(ServiceNames.ServiceB);
Bind<IService>().To<ServiceDefault>()
    .Named(ServiceNames.ServiceDefault);

Bind<IService>().ToProvider<ServiceProvider>()
    .When(request => request.Constraint == null);
如果这不适用于您的场景,因为请求除了名称之外还有其他约束,那么您可以采用基于参数的解决方案。对于感兴趣的读者,简而言之,其工作原理如下:

  • 创建包含名称的自定义实现
  • 基于创建用于绑定的自定义扩展方法。这应该检查自定义参数是否在上下文中,以及字符串是否匹配。将此应用于所有“命名”服务绑定,而不是
    命名(…)
  • 调整提供程序以将自定义参数(带名称)添加到请求intead中,即通过
    .Named(…)
    为ninject提供“名称”以供选择

@i-one如果简单的解决方案对您不起作用,并且自定义实现的说明不够具体,我很乐意提供一个完整的实现。我发现
When(request=>request.Target!=null)
在我的情况下也能起作用,而
whenInjectedTo()也能起作用。
(不过这一点看起来并不聪明)。当(request=>request.Constraint==null)
解决方案被包装到扩展方法中时,您能帮我包装一下您的
吗?我对Ninject绑定语法基础结构有点迷茫。另外,对于
request.Target!=null
request.Constraint==null
谓词,如果使用一个谓词而不是另一个谓词,会有什么区别?执行
kernel.Get()
request.Target
变为
null
。因为没有可注入的目标。执行
kernel.Get(“foo”)
kernel.Get(metadata=>true)
发出
request.Constraint
not
null
@i-one使用替代解决方案和扩展方法更新了答案。
Bind<IService>().ToProvider<ServiceProvider>()
    .WhenInjectedInto(typeof(ServiceUse), typeof(AnotherServiceUse));
Bind<IService>().ToProvider<ServiceProvider>()
    .WhenInjected(); //target is not matter
Bind<IService>().To<ServiceA>()
    .Named(ServiceNames.ServiceA);
Bind<IService>().To<ServiceB>()
    .Named(ServiceNames.ServiceB);
Bind<IService>().To<ServiceDefault>()
    .Named(ServiceNames.ServiceDefault);

Bind<IService>().ToProvider<ServiceProvider>()
    .When(request => request.Constraint == null);
Bind<IService>().ToProvider<ServiceProvider>()
    .When(request => true);
public static class NinjectExtensions
{
    public static IBindingInNamedWithOrOnSyntax<T> MakePreferredBinding<T>(
        this IBindingWhenSyntax<T> syntax)
    {
        return syntax.When(req => true);
    }
}