2016-05-17 16 views
0

私は複数の実装を持つインターフェースを持っています。これらの実装は、名前のバインディングを経由して設定されていますNinjectで名前付きバインディングを飾る方法

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>(); 

私は結合WhenParentNamedWhenAnyAncestorNamed文脈があることを知っているが、彼ら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見てきましたが、それは名前のバインディングを扱っていないので、該当するようではありません。

​​

更新

理想的には、このようなものになるだろう

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を構築しようとすると、2つのマッチングバインディングがあるということです。 1つは具体的な実装(「First」という名前の場合はFirstService)、もう1つはFirstDecoratorです。私が終わった

+0

Ninject

にプル要求として提出することができるかどうかを確認するためにことになるだろう

あなたはどのようにサービスを解決すると思いますか? '(" First ")'を呼び出すことによって? –

+0

修正。その情報で質問を更新します – cidthecoatrack

答えて

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型句にこれをリファクタリングして
関連する問題