2010-02-09 10 views
61

Postanowiłem zacząć używać Ninject i napotkać problem. Załóżmy, że mam następujący scenariusz. Mam interfejs IService i 2 klasy implementujące ten interfejs. A także mam klasę, której konstruktor otrzymuje IService i int. W jaki sposób mogę utworzyć instancję tej klasy przy pomocy Ninject (nie chcę sztywno tego int, chcę go przekazać za każdym razem, gdy otrzymam instancję)?Tworzenie instancji za pomocą Ninject z dodatkowymi parametrami w konstruktorze

Oto niektóre kodu ilustrujący sytuację:

interface IService 
{ 
    void Func(); 
} 

class StandardService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Standard"); 
    } 
} 

class AlternativeService : IService 
{ 
    public void Func() 
    { 
     Console.WriteLine("Alternative"); 
    } 
} 


class MyClass 
{ 
    public MyClass(IService service, int i) 
    { 
     this.service = service; 
    } 

    public void Func() 
    { 
     service.Func(); 
    } 

    IService service = null; 
} 
class Program 
{ 
    static void Main(string[] args) 
    { 
     IKernel kernel = new StandardKernel(new InlineModule(
      x => x.Bind<IService>().To<AlternativeService>(), 
      x => x.Bind<MyClass>().ToSelf())); 

     IService service = kernel.Get<IService>(); 

     MyClass m = kernel.Get<MyClass>(); 
     m.Func(); 
    } 
} 

Odpowiedz

84

With.ConstructorArgument istniał w 1,0 do tego celu. W wersji 2.0, składnia zmieniła się nieznacznie: - With.Parameters.ConstructorArgument with ninject 2.0

Zobacz Inject value into injected dependency więcej szczegółów i przykładów w jaki sposób korzystać z kontekstu, dostawcy i argumenty, aby przekazać takie rzeczy wokół bardziej poprawnie.

EDIT: Jak Steven wybrał udawać mój komentarz nie ma znaczenia, ja najlepiej wyjaśnić, co mówię z niektórymi przykładami (do 2,0):

MyClass m = kernel.Get<MyClass>(new ConstructorArgument("i", 2)); 

który do moich oczu jest bardzo jasne i stwierdza dokładnie, co się dzieje.

Jeśli jesteś w sytuacji, w której można określić parametr w bardziej globalnym sposób można zarejestrować dostawcę i zrobić to tak:

class MyClassProvider : SimpleProvider<MyClass> 
{ 
    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), CalculateINow()); 
    } 
} 

i zarejestrować go tak:

x => x.Bind<MyClass>().ToProvider(new MyClassProvider()) 

NB bit CalculateINow() to miejsce, w którym można umieścić logikę tak, jak w pierwszej odpowiedzi.

lub uczynić to bardziej skomplikowane tak:

class MyClassProviderCustom : SimpleProvider<MyClass> 
{ 
    readonly Func<int> _calculateINow; 
    public MyClassProviderCustom(Func<int> calculateINow) 
    { 
     _calculateINow = calculateINow; 
    } 

    protected override MyClass CreateInstance(IContext context) 
    { 
     return new MyClass(context.Kernel.Get<IService>(), _calculateINow()); 
    } 
} 

które chcesz zarejestrować tak:

x => x.Bind<MyClass>().ToProvider(new MyClassProviderCustom(() => new Random().Next(9))) 

UPDATE: Nowsze mechanizmy, które wykazują znacznie lepsze wzorce z mniejszym boilerplate niż wymienione powyżej są zawarte w rozszerzeniu Ninject.Extensions.Factory patrz: https://github.com/ninject/ninject.extensions.factory/wiki

Jak stwierdzono wcześniej, if you need to pass a different parameter each time and you have multiple levels in the dependency graph, you might need to do something like this.

Ostatnim czynnikiem jest to, że ponieważ nie określono Using<Behavior>, to będzie domyślnie domyślnie jak określono/domyślnie w opcji dla jądra (TransientBehavior w próbce), które mogłyby uczynić fakt, że fabryka oblicza i w locie [np. jeśli obiekt był buforowany]

Teraz, aby wyjaśnić kilka innych punktów w komentarzach, które są fałszywe i pomijane. Kilka ważnych rzeczy do rozważenia na temat korzystania z DI, czy to Ninject lub czegokolwiek innego, co ma na celu:

  1. mieć jak najwięcej jak to możliwe, wykonywana przez wstrzyknięcie konstruktora, więc nie trzeba używać dodatkowych atrybutów kontenerowych i sztuczki.Jest dobry wpis na blogu o nazwie Your IoC Container is Showing.

  2. Zminimalizuj kod przechodzący do kontenera i pytaj o rzeczy - w przeciwnym razie twój kod jest połączony z a) konkretnym kontenerem (który CSL może zminimalizować) b) sposobem, w jaki jest ułożony cały twój projekt. Istnieją dobre posty na blogu, które pokazują, że CSL nie robi tego, co myślisz. Ten ogólny temat jest określany jako Service Location vs Dependency Injection. AKTUALIZACJA: Aby uzyskać szczegółowe i pełne uzasadnienie, patrz: http://blog.ploeh.dk/2011/07/28/CompositionRoot.aspx.

  3. Minimalizacja wykorzystania statyki i pojedynczych

  4. Nie należy zakładać, że jest tylko jeden [global] Pojemnik i że jest OK, po prostu zażądać go, gdy jest to potrzebne jak miły zmiennej globalnej. Prawidłowe użycie wielu modułów i Bind.ToProvider() udostępnia strukturę do zarządzania tym. W ten sposób każdy oddzielny podsystem może działać na własną rękę, a przyzwyczajenie się elementy niskopoziomowe są przywiązane do składników najwyższego poziomu, itd

Jeśli ktoś chce wypełnić linki do blogów, mam na myśli doceniam to (wszystkie są już połączone z innymi wpisami na SO, więc to wszystko jest tylko powieleniem wprowadzonym przez UI w celu uniknięcia pomyłki wprowadzającej w błąd odpowiedzi).

Teraz , gdyby tylko Joel mógł wejść i naprawdę ustawić mnie na właściwej składni i/lub na właściwej drodze!

UPDATE: Ta odpowiedź jest wyraźnie użyteczne od liczby upvotes to zdobył, chciałbym przedstawić następujące zalecenia:

  • Powyższy czuje się jak to jest nieco przestarzałe i szczerze mówiąc odzwierciedla wiele niekompletnego myślenia, które niemal wydaje się zawstydzające od przeczytania Dependency Injection in .net - Biegnij i kup teraz - nie chodzi tylko o DI, pierwsza połowa to kompletne potraktowanie wszystkich problemów związanych z architekturą otaczających go od człowieka, który spędził tu zbyt dużo czasu wokół znacznika wtrysku zależności.
  • Go czytać Mark Seemann's top rated posts here on SO right now - dowiesz się cennych technik z każdego jednego
+0

Dobrego znaleźć to, ponieważ dokumentacja jest tak daleko w tyle .... – Elton

Powiązane problemy