2011-10-31 3 views
8

나는 서비스의 여러 구현을 바인딩 할 한 번에 호출 모두 있습니다Ninject에 멀티 캐스팅

var kernel = new StandardKernel(); 

kernel.Bind<IBreakfast>.To<Spam>(); 
kernel.Bind<IBreakfast>.To<Eggs>(); 
kernel.Bind<IBreakfast>.To<MoreSpam>(); 

kernel.Get<IBreakfast>().Eat(); // call Eat method on all three bound implementations 

Ninject에 그렇게하지 않고, 여러 바인딩을 가진에 대한 예외를 던질 것이다. 그 오류를 해결할 수있는 방법이 있습니까, 그리고 모든 구현을 호출해야합니까?

또한 Bind<> 호출은 런타임에로드 될 수도 있고로드되지 않을 수도있는 다른 프로젝트에있을 수 있으므로 호출하기 위해 단일 구현을 만드는 것은 작동하지 않습니다. 이것은 ASP.NET MVC 3 웹 사이트 용 플러그인 아키텍처의 일부입니다.

답변

12

생성자 삽입을 사용하고 List<IBreakfast> 매개 변수가있는 경우 Ninject는 모든 바인딩을 사용하여 목록을 구성합니다. 이 경우 Eat으로 전화 할 수 있습니다.

이 패턴을 사용하여 Ninject가 예를 들어 플러그인 목록을 만들 수 있습니다.

[Test] 
    public void Test() 
    { 
     IKernel kernel = new StandardKernel(); 

     kernel.Bind<IBreakfast>().To<Eggs>(); 
     kernel.Bind<IBreakfast>().To<Spam>(); 
     kernel.Bind<IBreakfast>().To<MoreSpam>(); 

     var bling = kernel.Get<Bling>(); 
    } 

    private class Bling 
    { 
     public Bling(List<IBreakfast> things) 
     { 
      things.ForEach(t => t.Eat()); 
     } 
    } 

    private interface IBreakfast 
    { 
     void Eat(); 
    } 

    private class Ingrediant : IBreakfast 
    { 
     public void Eat(){Console.WriteLine(GetType().Name);} 
    } 

    private class Eggs : Ingrediant{} 
    private class Spam : Ingrediant{} 
    private class MoreSpam : Ingrediant { } 

출력 :

계란
스팸
MoreSpam이

+0

아침에 이것을 시도 하겠지만, 바인딩 <> ('두 번째 호출에 오류가 발생해서 Ninject하지 않습니다) .To <>()'? – MikeWyatt

+5

@MikeWyatt : 아니요, 여러 개의 Bind가 좋습니다. 좋지 않은 것은'Get '이'Single '항목 이상을 산출하는 것입니다. 원하는 경우'GetAll '을 사용하거나'List ','T []'또는'IEnumerable '을 통해 여러 등록을 암시 적으로 일괄 처리 할 수 ​​있습니다.) (그리고 게시/코드 테스트는 결코 폭발물을 게시하지 않습니다!). Ninject는 원하는 방식으로 호출을 멀티 캐스트하기 위해 암시 적 컴포지트를 생성하는 데 많은 어려움을 겪지 않습니다. –

+1

위대한 작품입니다. 감사. – MikeWyatt

0

당신은 많은 구체적인 클래스에 한 번에 하나의 인터페이스를 바인딩 할 수 없습니다, 그 DI 규칙에 대해입니다.

기본적으로 원하는 것은 몇 가지 구체적인 인스턴스를 초기화하고 해당 메서드를 호출하는 것입니다.

당신이 체크 아웃 할 수 있습니다 : 나는 일을 얻을 때

Bind<IBreakfast>.To<Spam>().Named("Spam"); 
Bind<IBreakfast>.To<Eggs>().Named("Eggs"); 
Bind<IBreakfast>.To<MoreSpam>().Named("MoreSpam"); 

var breakfastList = new List() { "Spam", "Eggs", "MoreSpam" }; 
breakfastList.ForEach(item => kernel.Get<IBreakfast>(item).Eat()); 
+0

DI 규칙에 위배되는 것은 아닙니다. 문제 영역이 자연스럽게 인터페이스와 구체적인 클래스 사이에 잠재적 인 1 대 다 관계가되는 경우에는 괜찮습니다. Decent IoC 컨테이너를 사용하면이 시나리오를 모델링 할 수 있습니다. OP의 플러그인 시나리오는 이러한 유형의 모델 중 하나입니다. –

+3

이 접근법은 플러그인 아키텍처에서 작동하지 않습니다. 정의에 따라 어떤 플러그인이 제공 될지 모르기 때문입니다. – Bevan