我有一个有多个实现的接口。这些实现是通过命名绑定设置的:
Bind<IService>().To<FirstService>().Named("First");
Bind<IService>().To<SecondService>().Named("Second");
Bind<IService>().To<ThirdService>().Named("Third");
但是,每个服务都需要进行装饰:
Bind<IService>().To<FirstService>().WhenInjectedInto<FirstDecorator>();
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>();
Bind<IService>().To<SecondDecorator>();
我知道有WhenParentNamed
和WhenAnyAncestorNamed
内容绑定,但它们似乎与WhenInjectedInto
互斥。如何设置Ninject以便它既可以装饰也可以命名绑定?我有一个Provider
方案设置确实有效,但我想知道是否有办法在Ninject中本地执行此操作,而不使用自定义提供程序。
Bind<IService>().ToProvider(new ServiceProvider("First")).Named("First");
Bind<IService>().ToProvider(new ServiceProvider("Second")).Named("Second");
Bind<IService>().ToProvider(new ServiceProvider("Third")).Named("Third");
class ServiceProvider : Provider<IService>
{
private readonly string name;
public ServiceProvider(string name)
{
this.name = name;
}
protected override CreateInstance(IContext context)
{
var service = GetService(name);
var otherDependency = context.Kernel.Get<OtherDependency>();
service = new FirstDecorator(service, otherDependency);
service = new SecondDecorator(service);
return service;
}
private IService GetService(string name, IContext context)
{
switch(name)
{
case "First": return context.Kernel.Get<FirstService>();
case "Second": return context.Kernel.Get<SecondService>();
case "Third": return context.Kernel.Get<ThirdService>();
default: throw new ArugmentException($"No binding for {name}");
}
}
}
我查看了this,但由于它没有处理命名绑定,因此它似乎不适用。
理想情况下,它会是这样的:
Bind<IService>().To<FirstService>().WhenInjectedInto<FirstDecorator>().Named("First");
Bind<IService>().To<SecondService>().WhenInjectedInto<FirstDecorator>().Named("Second");
Bind<IService>().To<ThirdService>().WhenInjectedInto<FirstDecorator>().Named("Third");
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>();
Bind<IService>().To<SecondDecorator>();
更新:以下是我希望调用其中一种装饰服务的方法:
kernel.Get<IService>("First");
或
[Inject, Named("First")]
public IService Service {get; set;}
最后一个是自动集成测试。
更新2 :我已经尝试了这个,它不起作用(抱怨重复绑定,大概是因为它没有尊重具体实现绑定上的名称)
Bind<IService>().To<FirstService>().WhenInjectedInto<FirstDecorator>().Named("First");
Bind<IService>().To<SecondService>().WhenInjectedInto<FirstDecorator>().Named("Second");
Bind<IService>().To<ThirdService>().WhenInjectedInto<FirstDecorator>().Named("Third");
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>().Named("First");
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>().Named("Second");
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>().Named("Third");
Bind<IService>().To<SecondDecorator>().Named("First");
Bind<IService>().To<SecondDecorator>().Named("Second");
Bind<IService>().To<SecondDecorator>().Named("Third");
更新3:执行以下ALMOST工作:
Bind<IService>().To<FirstService>().WhenAnyAncestorNamed("First");
Bind<IService>().To<SecondService>().WhenAnyAncestorNamed("Second");
Bind<IService>().To<ThirdService>().WhenAnyAncestorNamed("Third");
Bind<IService>().To<FirstDecorator>().WhenInjectedInto<SecondDecorator>().Named("First");
Bind(typeof(IService)).To(typeof(SecondDecorator)).Named("First");
Bind(typeof(IService)).To(typeof(SecondDecorator)).Named("Second");
Bind(typeof(IService)).To(typeof(SecondDecorator)).Named("Third");
问题在于,当它尝试构建SecondDecorator
时,有两个匹配的绑定:一个到具体实现(如果命名为“First”,然后是FirstService
),一个到{ {1}}。
答案 0 :(得分:0)
我最终手工制作了自己的装饰方法:
public override void Load()
{
var decorators = new[]
{
typeof(FirstDecorator),
typeof(SecondDecorator)
};
Decorate<IService, FirstService>("First", decorators);
Decorate<IService, SecondService>("Second", decorators);
Decorate<IService, ThirdService>("Third", decorators);
}
private void Decorate<S, T>(string name, params Type[] decorators)
where T : S
{
var allImplementations = new[] { typeof(T) }.Union(decorators);
foreach (var implementation in allImplementations)
{
Bind<S>().To(implementation).When(r => Need(implementation, r, name, allImplementations));
}
Bind<S>().To(allImplementations.Last()).Named(name);
}
private bool Need(Type implementation, IRequest request, string name, IEnumerable<Type> implementations)
{
var implementationsList = implementations.ToList();
var depth = implementationsList.Count - implementationsList.IndexOf(implementation);
return request.Depth == depth && request.ActiveBindings.Any(b => b.Metadata.Name == name);
}
我将查看是否可以将其重构为When
- 类型子句并作为拉取请求提交给Ninject