2012-02-14 2 views
5

Ninject를 시험해보고 있으며 구조도를 사용하여 코드 작성을 쉽게 수정했습니다. 이 기본 코드에서 구조 맵 레지스트리를 통해 다른 구성을 가진 객체 그래프를 사용하고 런타임에 데이터베이스의 값을 통해 사용되는 객체를 선택합니다 (이 경우 일부 객체가 삽입 된 wcf 서비스 본문을 다시 가져 오기 위해 사용됨) . 예를 들어 (구조 맵 코드 사용) :IoC를 사용하여 인스턴스를 구별하기 위해 이름 사용

레지스트리 1은 IBusinessContext, IRules 및 ILogger 유형의 모든 기본값을 설정합니다. 이것은 GenericContext/Logger/Rules 유형을 다른 전문화가없는 인터페이스와 함께 추가하는 것입니다.

public GenericRegistry() 
    { 
     // Set up some generic bindings here 
     For<ILogger>().Use<Loggers.GenericLogger>(); 
     For<IBusinessRule>().Use<Rules.StandardRule>(); 
     For<IBusinessContext>().Use<Contexts.GenericBusinessContext>(); 
     For<ILoggerContext>().Use<Loggers.GenericLoggerContext>(); 
    } 

레지스트리 2 세트까지 IBusinessContext는 SpecialisedContext 클래스를 사용하고 SpecializedLogger를 사용하는 ctor에 지시합니다. IBusinessContext의 인스턴스 이름은 "SpecializedContext"입니다.

이 모든 것이 구조 맵에서 예상대로 작동합니다 (이전 구문 또는 새 구문에 따라 다름).

그러나 Ninject를 사용했을 때 이름없는 인스턴스가 기본이 될 것으로 예상하여 문제가 발생했습니다 (Ninject의 작동 방식이 아니라는 사실을 알고 있습니다). 이로써 명명 된 인스턴스를 사용하는 것이 정말 나쁜 아이디어라는 일부 연구가 이루어졌습니다. 자동 등록 또는 속성을 사용하여 이름을 설정하거나 특정 유형을 요청하는 더 나은 방법이 있지만 시스템에서 런타임에 필요한 구성을 파악할 수있는 방법이 필요하다고 설명합니다. (그리고 IoC 프레임 워크가 등록 된 유형 또는 규칙을 기반으로 나머지를 파악하도록하십시오).

그래서 ... 여기에 IoC 개념을 잘못 사용하고 있습니다. 이름으로 내 최상위 개체를 물어볼 생각입니까? 아니면 일반적으로 내가하려는 일을하는 더 좋은 방법입니까? 대신 MEF와 같은 것을 사용하고이 플러그인을 모두 플러그인으로 취급해야합니까?

스트레스 팩토리처럼 이것을 사용하지 않고 컨테이너의 x 유형 인스턴스에 대한 코드의 각 레벨을 묻는 것은 시작 액션 일뿐입니다.

시간에 미리 감사드립니다 그리고 그것이 당신이 IMO 필요 무엇 달성 할 수있는 유일한 방법 인 경우, 이름 Ninject에 바인딩을 설정하는 모든 것을 아무 문제가 없습니다 :

답변

3

도움이됩니다.

Bind<IBusinessContext>().To<ConcreteBusinessContext>().Named("XYZ"); 

또는 다른 바인딩을 얻기 위해 특정 호출 클래스를 필요로하는 경우 당신은 시도 할 수 있습니다 :

그래서 기본 구문은

Bind<IIBusinessContext>().To<SomeOtherConcreteBusinessContext>().WhenInjectedInto<TypeOfCallingClass>(); 

을하지만, 호출 클래스 (I 경우 그것의 ctor에있는 IBusinessContext를 가진 클래스에 대해 이야기하는 것)은로드 할 구체적인 유형을 결정하는 구성 값을 제공하므로 델리게이트를 사용해야합니다.

Bind<Func<string, IBusinessContext>>().ToMethod(ctx => str => DetermineWhichConcreteTypeToLoad(ctx, str)); 

//messy sudo code 
static DetermineWhichConcreteTypeToLoad(IContext ctx, string str) 
{ 
    if(str == "somevalue"){ 
     return ctx.Kernel.Get<ConcreteType1>(); 
    else 
     return ctx.Kernel.Get<ConcreteType2>(); 
} 
당신이 특정 구체적인 유형을로드하는 방법을 가지고 명명 된 인스턴스에 대한 필요가 없습니다 그 예에서

class DoStuff 
{ 
    Func<string, IBusinessContext>> contextFunc; 

    DoStuff(Func<string, IBusinessContext>> contextFunc) 
    { 
     this.contextFunc = contextFunc; 
    } 

    void SomeMethod() 
    { 
     var configuredValue = GetConfiguredValueSomehow(); 
     var context = contextFunc(configuredValue); //<-- this passes your config value back to ninject in the ToMethod() lambda 
     //do something with context 
    } 
} 

그러나 당신은 여전히 ​​경우 명명 된 인스턴스를 사용할 수 있습니다 : 같은

하고 호출 클래스는 보일 것이다

Bind<IBusinessContext>().To<ConcreteBusinessContext>().Named("config1"); 
Bind<IBusinessContext>().To<SomeOtherBusinessContext>().Named("config2"); 

Bind<Func<string, IBusinessContext>>().ToMethod(ctx => str => ctx.Kernel.Get<IBusinessContext>().Named(str)); 

class DoStuff 
{ 
    Func<string, IBusinessContext>> contextFunc; 

    DoStuff(Func<string, IBusinessContext>> contextFunc) 
    { 
     this.contextFunc = contextFunc; 
    } 

    void SomeMethod() 
    { 
     var configuredValue = "config1"; 
     var context = contextFunc(configuredValue); //<-- this will passthrough "config1" to the above ToMethod() method and ask for a IBusinessContext named "config1" 

    } 
} 

편집 : 당신이 그런 짓을 할 나는 당신의 설정 값 나던 호출 코드에서 온 경우, 다음이 일이 훨씬 쉽게 언급하는 것을 잊었다. 귀하의 코드 대신 같은 것을 볼 수 있습니다 : 당신은 마법 문자열을 사용하기보다는 창의적이고이 될 수

// this method can just be a global method in you app somewhere 
static string GetConfigValue() 
{ 
    //something like 
    return AppSetting.Get("config"); 
} 

Bind<IBusinessContext>().To<ConcreteBusinessContext>().When(r => GetConfigValue() == "config1"); 
Bind<IBusinessContext>().To<SomeOtherBusinessContext>().When(r => GetConfigValue() == "config2"); 

class DoStuff 
{ 
    IBusinessContext context; 

    DoStuff(BusinessContext context) 
    { 
     this.context = context; 
    } 

    void SomeMethod() 
    { 
     //use the context value as you normally would 
    } 
} 

를, 당신의 설정 방법은 열거를로드 할 수 있습니다와() 메소드는 대신 열거에 대해 평등을 테스트 할 수 있습니다 문자열,하지만 당신은 아이디어를 얻을. 이것은 ninject에서 컨텍스트 바인딩으로 알려져 있으며 SM의 한 번 열렬한 사용자라고 말할 수 있습니다. SM보다 훨씬 강력합니다. 나머지 When() 메서드를 체크 아웃하고 수행 할 수있는 작업을 확인하십시오.

+0

감사합니다. Aaron! 그것은 나를 위해 몇 가지를 정리했습니다 :) 그것은 매우 감사합니다. – NoodleAwa

관련 문제