2012-09-05 16 views
15

Mam projekt, w którym Ninject jest używany jako kontener IoC. Obawiam się, że wiele klas mają taki rodzaj konstruktorów:Lazy Dependency Dependency

[Inject] 
public HomeController(
    UserManager userManager, RoleManager roleManager, BlahblahManager blahblahManager) { 
    _userManager = userManager; 
    _roleManager = roleManager; 
    _blahblahManager = blahblahManager; 
} 

Co jeśli nie chcę, aby wszystkie instancje tych klas na raz?

Sposób, w jaki wszystkie te klasy są pakowane przez Lazy<T> i przekazywane do konstruktora, nie jest dokładnie tym, czego potrzebuję. Instancje T nie zostały jeszcze utworzone, ale instancje Lazy<T> są już przechowywane w pamięci.

Mój kolega sugeruje, żebym używał wzoru Fabryki do kontrolowania wszystkich wystąpień, ale nie jestem pewien, czy IoC ma tak świetny błąd w projektowaniu.

Czy istnieje obejście tego problemu, czy IoC ma tak dużą wadę w swoim projekcie? Może powinienem użyć innego pojemnika IoC?

Wszelkie sugestie?

+0

Jaki jest twój problem? Dlaczego nie chcesz tych instancji? –

+2

Mogę chcieć UserManager podczas pracy kontrolera, ale RoleManager nie jest potrzebny i na odwrót. Jeśli mówisz o instancjach Lazy , to nie jest wielka sprawa, aby je mieć w pamięci, ale czy to jedyny sposób? – xwrs

+1

Dlaczego jest to wielka sprawa dla 'UserManager' i' RoleManager'? Twoi konstruktorzy i tak nie powinni wykonywać ciężkiej pracy. –

Odpowiedz

36

Wydaje mi się, że robisz premature optimization: nie rób tego.

Konstruktorzy twoich usług powinni wykonać nothing more, niż przechowywać zależności, które pobiera w polach prywatnych. W takim przypadku stworzenie takiego obiektu jest naprawdę niewielkie. Nie zapominaj, że tworzenie obiektów w .NET jest naprawdę szybkie. W większości przypadków, z perspektywy wydajności, po prostu nie ma znaczenia, czy te zależności zostaną wstrzyknięte, czy nie. Szczególnie w porównaniu do ilości obiektów, reszta aplikacji (i frameworki, których używasz) wypluwają. Rzeczywiste koszty powstają, gdy zaczynasz korzystać z usług internetowych, baz danych lub systemu plików (lub ogólnie z I/O), ponieważ powodują one znacznie większe opóźnienie.

Jeśli tworzenie jest naprawdę drogie, zwykle ukrywaj kreację za Virtual Proxy zamiast wstrzykiwać Lazy<T> w każdym kliencie, ponieważ pozwala to zwykłemu kodowi aplikacji pozostać obojętnym na fakt, że istnieje mechanizm opóźniający tworzenie (zarówno kod aplikacji, jak i kod testowy stają się coraz bardziej złożone, gdy to robisz).

Rozdział 6 z Dependency Injection in .NET, second edition zawiera bardziej szczegółową dyskusję na temat leniwych i wirtualnych serwerów proxy.

Jednakże Lazy<T> zużywa tylko 20 bajtów pamięci (a na jego kolejny 24 bytes owinięty Func<T>, zakładając, że proces 32-bitowy), i utworzenie przykład Lazy<T> jest prawie bezpłatne. Nie musisz się tym martwić, z wyjątkiem sytuacji, gdy jesteś w środowisku z bardzo ograniczonymi ograniczeniami pamięci.

Jeśli zużycie pamięci stanowi problem, spróbuj zarejestrować usługi o czasie życia dłuższym niż przejściowy. Możesz to zrobić na żądanie, na żądanie internetowe lub na singleton. Powiedziałbym nawet, że gdy znajdujesz się w środowisku, w którym tworzenie nowych obiektów jest problemem, prawdopodobnie powinieneś używać tylko usług singleton (ale jest mało prawdopodobne, że pracujesz nad takim środowiskiem, ponieważ budujesz aplikację internetową) .

Należy zauważyć, że Ninject jest jedną z wolniejszych bibliotek DI dla .NET. Jeśli to Cię niepokoi, switch to a faster container. Niektóre pojemniki mają wydajność zbliżoną do ręcznego tworzenia wykresów obiektów. ale na wszelkie sposoby, zrób to, wielu programistów przełącza biblioteki DI z niewłaściwych powodów.

Należy zauważyć, że używanie Lazy<T> jako zależności to leaky abstraction (naruszenie Dependency Inversion Principle). Przeczytaj this answer, aby uzyskać więcej informacji.

+0

Dziękuję. Sprawiłeś, że moje zrozumienie sytuacji stało się bardziej jasne. – xwrs

+0

Nie sądzę, że to przedwczesna optymalizacja, z tym argumentem wydaje się, że nigdy nie ma potrzeby, aby Lazy, tworzenie jednego obiektu nie jest ciężkie, ale nie wiesz, ile obiektów tworzy w swoim konstruktorze. I otwarcie jakiegoś zdalnego zasobu, którego nie można użyć. –

0

New

Steven ma rację mówiąc, że to wygląda jak przedwczesny optymalizacji. Konstrukcja tych obiektów jest bardzo szybka i zwykle nie jest wąskim gardłem.

Jednak używanie Lazy do wyrażania zależności, której nie potrzebujesz od razu, jest typowym schematem w ramach Dependency Injection. Actofac to jeden taki kontener, który ma wbudowaną obsługę various wrapping types. Jestem pewien, że istnieje również rozszerzenie dla Ninject, może spojrzeć na to, Ninject Lazy.

+1

Fakt, że kontenery DI obsługują Lazy , nie pozwala, aby kod aplikacji był zależny od zależności Lazy . Wiele kontenerów DI obsługuje funkcje, które nie promują najlepszych praktyk. Z perspektywy Dependency Injection, Lazy jest nieszczelną abstrakcją. Przeczytaj [to] (https://stackoverflow.com/a/21724609/264697), aby uzyskać wyjaśnienie, dlaczego Lazy przecieka. – Steven

Powiązane problemy