2013-05-31 15 views
8

Mam klasę statyczną i muszę wstrzyknąć do niej kilka instancji. Klasa statyczna może mieć konstruktor statyczny, ale musi być bez parametrów. Więc w jaki sposób mam coś w nim wprowadzić?Klasy naukowe i statyczne - jak?

Nie chcę tworzyć singletonów. Chciałbym mieć klasę statyczną, a jedna z jej metod działa na instancji, która powinna zostać wstrzyknięta. Bellow jest przykładem tego, czego potrzebuję.

public static class AuthenticationHelper 
{ 
    // Fields. 
    private static object _lock = new object(); 
    private static readonly UserBusiness _userBusiness; // <-- this field needs to be injected. 

    // Public properties. 
    public static User CurrentUser 
    { 
     get 
     { 
      if (IsAuthenticated) 
      { 
       User user = (User)Context.Session[SessionKeys.CURRENT_USER]; 

       if (user == null) 
       { 
        lock (_lock) 
        { 
         if (user == null) 
         { 
          user = _userBusiness.Find(CurrentUserId); 
          Context.Session[SessionKeys.CURRENT_USER] = user; 
         } 
        } 
       } 

       return user; 
      } 

      return null; 
     } 
    } 
    public static int CurrentUserId { get; /* implementation omitted for brevity */ } 
    public static bool IsAuthenticated { get; /* implementation omitted for brevity */ } 
} 

Informacje dodatkowe: jest to aplikacja MVC4, więc używam wtyczki ninject.mvc3.

PS: Widziałem kilka pytań dotyczących metod Ninject i statycznych, ale żaden z nich nie zajmował się takim problemem.

Z góry dziękuję.

Odpowiedz

16

Nie rób tego. Nie używaj klasy statycznej, która wymaga własnych zależności. To sprawia, że ​​testowanie jest trudniejsze, a inne typy zależne od tego AuthenticationHelper nie będą mogły uwzględnić go w swoim konstruktorze, co oznacza, że ​​ukrywają fakt, że od niego zależą.

Zamiast tego rób to, co zawsze robisz: spraw, aby AuthenticationHelper był niestatyczny, zaimplementuj na nim interfejs IAuthenticationHelper i wstrzyknij wszystkie zależności za pośrednictwem publicznego konstruktora.

Ale jeśli nalegasz na zachowanie tej klasy statycznej (co znowu jest naprawdę złym pomysłem), utwórz na niej statyczną metodę Initialize(UserBusiness userBusiness) i wywołaj tę metodę w ścieżce początkowej swojej aplikacji. Nie możesz pozwolić swojemu kontenerowi DI wywołać tej statycznej metody. Nie pozwalają na to, ponieważ: 1. jest to zły pomysł, i 2. taka statyczna metoda musi zostać wywołana tylko raz, więc pozwolenie na to, aby twój automatyczny przewód nie był naprawdę pomocny.

+0

widzę. Nie zdawałem sobie sprawy, że to taka zła praktyka, ale dzięki waszemu wyjaśnieniu mogę ją teraz zrozumieć i postąpię zgodnie z waszą radą. W każdym razie, dobrze jest wiedzieć, jak to obejść, jeśli nie ma innej opcji. Dzięki! –

+1

To prawda, czasami nie możesz. Na przykład przy wprowadzaniu Dependency Injection w starszych aplikacjach będziesz musiał wykonać małe kroki. Jednym z takich tymczasowych kroków może być takie rozwiązanie. To brzydkie, to techniczne, ale tymczasowe (przynajmniej tak powinno być). Ale jeśli twoja aplikacja jest już zbudowana przy użyciu DI, naprawdę nie ma powodu, aby to zrobić. – Steven

1

Na marginesie, zamek jest całkowicie bezużyteczny, ponieważ blokujesz dostęp do zmiennej lokalnej "użytkownik", która nie zmieni się między liniami 2 "jeśli (użytkownik == zerowy)".

zamiarem jest, aby zablokować dostęp do [CURRENT_USER] elementu Context.Session, więc ..

  User user = (User)Context.Session[SessionKeys.CURRENT_USER]; 

      if (user == null) 
      { 
       lock (_lock) 
       { 
        user = (User)Context.Session[SessionKeys.CURRENT_USER]; 
        if (user == null) 
        { 
         user = _userBusiness.Find(CurrentUserId); 
         Context.Session[SessionKeys.CURRENT_USER] = user; 
        } 
       } 
      }