2012-02-14 8 views
5

Próbuję Ninject i modyfikuję kod, który napisałem z Mapą Struktury, aby zobaczyć, jak łatwo jest. W tym kodzie podstawowym mam wykres obiektów, które mają różne konfiguracje za pośrednictwem rejestrów mapy struktury, a ten, który ma być użyty, jest wybierany w czasie wykonywania przez wartość w bazie danych (w tym przypadku, aby wycofać ciało usługi wcf z zastrzykami niektórych obiektów) . Na przykład (przy użyciu kodu mapy struktury):Używanie nazw do rozróżniania instancji za pomocą IoC

Rejestr 1 ustawia wszystkie wartości domyślne dla typów IBusinessContext, IRules i ILogger. To jest po prostu dodanie typów GenericContext/Logger/Rules obok interfejsów bez żadnej specjalności.

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

Registry 2 ustanawia IBusinessContext użyć klasy SpecialisedContext i opowiada konstruktor korzystania SpecializedLogger. Instancja dla IBusinessContext nosi nazwę "SpecializedContext".

public SpecializedRegistry() 
    { 
     // Old style syntax as it affects the default for IBusinessContext 
     // Perhaps a hint at what I'm doing? 
     InstanceOf<IBusinessContext>().Is.OfConcreteType<Contexts.SpecializedBusinessContext>().Named(SpecializedInstanceName).Ctor<ILogger>().Is<Loggers.SpecialisedLogger>(); 
    } 

Wszystko działa zgodnie z oczekiwaniami w Mapie konstrukcji (w zależności od starej lub nowej składni).

Jednak, gdy używam programu Ninject, natrafiłem na problem z oczekiwaniem, że instancja nienazwana będzie domyślna (a nie jak działa Ninject, rozumiem). Doprowadziło to do pewnych badań, które zasugerowały, że używanie nazwanych wystąpień to naprawdę zły pomysł. Rozumiem, że istnieją lepsze sposoby, aby to zrobić za pomocą automatycznej rejestracji lub atrybutów, aby ustawić nazwę lub zażądać określonego typu, ale w systemie, który opisuję, musi istnieć sposób w czasie wykonywania, aby dowiedzieć się, o którą konfigurację poprosić. w górnej części drzewa (i niech struktura IoC oblicza resztę na podstawie zarejestrowanych typów lub reguł).

Więc ... czy używam tutaj koncepcji IoC nie tak, oczekując, że poprosię o mój obiekt najwyższego poziomu po imieniu, czy ogólnie jest lepszy sposób na robienie tego, co próbuję zrobić? Czy zamiast tego powinienem używać czegoś takiego jak MEF i traktować to wszystko jak wtyczki?

Podkreślam, że nie używam tego jako głupiej fabryki i pytam na każdym poziomie kodu dla instancji typu x z kontenera, to tylko działanie inicjujące.

góry dzięki za poświęcony czas i pomoc :)

Odpowiedz

3

Nie ma nic złego w ogóle, że utworzenie ninject powiązania z nazwy, jeśli jest to jedyny sposób, aby osiągnąć to, co jest potrzebne IMO.

Więc Podstawowa składnia to:

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

Lub jeśli potrzebujesz konkretnej klasy telefonicznej, aby uzyskać inny wiązanie to można spróbować:

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

Jednakże, jeśli klasa wywołujący (I "mówię o klasie, która ma IBusinessContext w swoim ctor) dostarcza wartość konfiguracyjną, która określa, który konkretny typ załadować, wtedy musisz użyć delegata:

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

i klasa wywołujący będzie wyglądać mniej więcej tak:

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 
    } 
} 

W tym przykładzie nie ma potrzeby dla nazwanych wystąpień, jak masz metodę, która ładuje specyficzny rodzaj betonu, jeśli jednak nadal można używać nazwanych wystąpień chcesz zrobić coś takiego:

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" 

    } 
} 

EDIT: Zapomniałem wspomnieć, że jeśli wartość config robi muszą pochodzić z kodu wywołującego, to sprawia, że ​​rzeczy o wiele łatwiejsze. Kod może zamiast wyglądać:

// 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 
    } 
} 

można być kreatywnym i zamiast używać magicznych ciągów, metoda config można załadować enum i sposób swoją Kiedy() może testować równości wobec enum zamiast ciąg, ale masz pomysł. Jest to znane jako bindowanie kontekstowe w ninject i mogę powiedzieć, że jako jeden raz zapalony użytkownik SM, jest to o wiele potężniejsze niż wszystko, co miało SM. Zrealizuj pozostałe metody When() i zobacz, co możesz zrobić.

+0

Dzięki Aaron! To wyjaśniło mi kilka rzeczy :) Jest to bardzo doceniane. – NoodleAwa

Powiązane problemy