Jak można wstrzyknąć zależność do języka? [Zamknięte]

10

Zastanawiałem się trochę nad tym, w jaki sposób zastrzyk zależności mógłby być lepiej zintegrowany bezpośrednio z językiem C #. Wymyśliłem potencjalne rozwiązanie, o którym chciałbym poznać Twoją opinię. Nie używałem wielu struktur wstrzykiwania zależności, więc może być coś, co przeoczam

W każdym razie chodzi o to, aby móc zadeklarować właściwości jako „wstrzykiwalne” za pomocą słowa kluczowego. Kiedy instancja obiektu jest tworzona, a ta właściwość nie jest inicjowana przez konstruktor lub inicjalizator obiektu, żąda instancji tego typu właściwości od jakiejś usługi globalnej.

Podobnie rejestrujesz procedury obsługi różnych typów dla tej usługi, aby można było utworzyć instancję typu wstrzykiwanej właściwości.

Zaletą korzystania z tego rodzaju architektury IMO jest to, że jest dość elastyczna i łatwa w użyciu. Minusem jest to, że za każdym razem, gdy inicjujesz klasę z zastrzykiem, może być pewne obciążenie wywołaniem singletona.

Z drugiej strony jest to problem tylko dla klas, które często są tworzone w rozwiązaniach o wysokiej wydajności, więc nie powinno to stanowić większego problemu. Być może w takich przypadkach możesz użyć jakiejś fabryki.

Myśl, problemy, pytania, lepsze pomysły?

Kod

public class SomeClass
{

  public SomeClass()
  {
     //implicit behavior if Animal is not set in constructor or initializer
    this.Animal =  GlobalInjector.Get(this,typeof(Mammal))

  }

  public injectable Mammal Animal  
  {
   get;
   set;
  }
}


 GlobalInjector.Register(typeof(Mammal), () => return new Mammal(someParameter));
Homde
źródło
Czy mógłbyś podać przykład pseudo kodu dla tych z nas, którzy nie znają DI? PS. Może mógłbyś również odpowiedzieć na moje pytanie dotyczące DI? :)
Steven
2
Nie jestem pewien, czy to rozumiem. Wszystko to można uzyskać za pomocą globalnego kontenera DI i atrybutu „[Zastrzyki]” zamiast słowa kluczowego, prawda?
nikie
Witam, Próbowałem pisać trochę o DI na swoje pytanie, nie jestem pewien, że odbiera to jednak
Homde
nikie: Tak, myślę, że mógłbyś wdrożyć rzeczywisty mechanizm na różne sposoby, jestem bardziej zainteresowany, jeśli podstawowa logika jest zdrowa
Homde 30.03.11
Czym zatem różni się ten istniejący IoC od twojego dodatkowego słowa kluczowego?
Matthew Whited

Odpowiedzi:

7

Są rzeczy, które należą do języków, i rzeczy, które nie. Dawno temu C uznał, że IO nie należało do tego języka, ponieważ jest on zewnętrzny w stosunku do modelu obliczeniowego i może być implementowany za pomocą bibliotek funkcji.

Wstrzykiwanie zależności jest właśnie takie. Jest niezależny od języka i można go wdrożyć za pomocą odpowiednich ram.

Jednym z problemów współczesnych języków jest to, że starają się robić za dużo. W końcu te języki upadają pod własnym ciężarem, gdy programiści uciekają do prostszych języków.

Wujek Bob.
źródło
Teoretycznie zgadzam się, że nie można mieć języka, w którym każda funkcja jest cechą języka bez rozdęcia. Zawsze jednak jest miejsce na nowe, wyższe abstrakcje, które pomagają nam pisać lepszy kod. Być może zastrzyk zależności sam w sobie nie jest problemem wymagającym rozwiązania, ale problemem, który rozwiązuje, a mianowicie sposobem na ułatwienie nam zmniejszenia zależności. To może nie być najlepszy sposób na zrobienie tego :)
Homde,
5

To nie jest potrzebne

Jedną z rzeczy, które najbardziej lubię w najlepszych frameworkach DI, których użyłem, jest to, że kod konfiguracyjny najwyższego poziomu jest jedyną częścią twojego kodu, która musi wiedzieć o DI. Automatyczne okablowanie odbywa się na poziomie kontenera i konfiguracji / „ładowania modułu”, a kod aplikacji może być całkowicie nieświadomy tego.

Oznacza to brak atrybutów, brak ciągów magicznych, brak konwencji. Każdy fragment kodu wie tylko, że akceptuje kod w swoim konstruktorze (/ właściwości / metody) i to wszystko.

Przy takim projekcie nie trzeba wcale zmieniać języka, aby obsługiwać Dependency Injection.

Jest to potencjalnie niebezpieczne

Najbardziej obawiam się, że zintegrowany z językiem system wstrzykiwania zależności polega na tym, że podniósłby on barierę przed jakimkolwiek innym wdrożeniem, ale prawdopodobnie pod pewnymi względami sam by się zamalował.

Oto kilka sposobów, w jakie może się zamalować w kącie:

  • Obsługuje tylko konfigurację opartą na XML lub tylko konfigurację opartą na kodzie
  • Brak możliwości czystego wsparcia fabrycznego wzorca projektowego (nie tylko składników przejściowych: komponentów generowanych w czasie wykonywania)
  • Jakoś zmieniając mój kod, więc byłem zmuszony użyć wstrzykiwania zależności i nie mogłem po prostu utworzyć instancji klasy dla testów jednostkowych
  • Nie obsługuje niestandardowych cykli życia
  • Nie podlega rozszerzeniu
  • Nie można go wymienić w przypadkach, gdy potrzebuję większej personalizacji
  • Bycie złamanym w jakiś sposób, którego jeszcze nie rozumiemy, ponieważ my .Net użytkownicy nie używali DI wystarczająco długo, aby poznać pułapki
Merlyn Morgan-Graham
źródło
4

Czy widziałeś Managed Extensibility Framework dostarczany z .NET 4? Oto artykuł, który napisałem z kilkoma przykładami. Zasadniczo jest to forma wstrzykiwania zależności wbudowana w .NET, z dodatkowymi funkcjami wykrywania w czasie wykonywania.

Zastrzyki z nieruchomości wyglądają następująco:

class Program
{
    [Import]
    public IMessageSender MessageSender { get; set; }
}

Zastrzyki dla konstruktorów wyglądają tak:

class Program
{
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    ...
    }
}

Możesz importować pola, importować opcjonalnie, importować kolekcje usług, w tym leniwe importowanie za pomocą metadanych, abyś mógł wyszukać odpowiednią usługę do utworzenia instancji. Możesz nawet ponownie zaimportować w czasie wykonywania, aby wyszukać nowe rozszerzenia.

Scott Whitlock
źródło
Podczas gdy MEF jest naprawdę fajny do pluginów, nie sądzę, że chciałbym go używać jako ogólnego mechanizmu DI
Homde
1
@MKO - Czy możesz wyjaśnić, czego brakuje? Zdaję sobie sprawę ze wszystkich artykułów, w których Glenn Block stara się uspokoić ludzi, że MEF nie zastąpi wszystkich frameworków DI, ale jeśli spojrzysz na szczegóły, to oczywiste, że jest to bardziej oświadczenie polityczne niż cokolwiek innego. Jeśli jednak możesz podać dobrą listę funkcji, których brakuje MEF w porównaniu z innymi strukturami DI, pomoże to ludziom podjąć świadomą decyzję. Poza tym pytanie dotyczy struktur DI w języku C #, a MEF jest wyraźnie kontenerem DI w środowisku .NET.
Scott Whitlock
2
  1. Tak naprawdę nie opisujesz mechanizmu konfiguracji, który IMHO jest trudnym zadaniem. Jak sprawić, aby cały kod działający w jednym wątku używał połączenia DB A i całego kodu w drugim wątku połączenia B? Jak zablokować wstrzyknięcie określonego zasobu, ponieważ użytkownik aktualnie zalogowany nie ma dostępu do niego?
  2. Nie używaj globalnego wtryskiwacza. Nie używaj żadnych globalnych rzeczy, możesz równie dobrze użyć zmiennych globalnych. Nie, używanie OOP-speak, takich jak singleton lub „static” zamiast global, nie zmienia ich globalnego charakteru.
  3. Rozważ pojemnik o dynamicznym zasięgu. Podczas gdy zakres leksykalny słusznie wygrał z zakresu dynamicznego, uważam, że zakres dynamiczny byłby dobrym zamiennikiem zakresu globalnego. Dziedziczenie różnicowe byłoby fajną implementacją (jak w dziedziczeniu opartym na prototypach).
  4. Uważam, że mechanizm DI oparty na języku powinien być naprawdę prosty, żadna z tych przedsiębiorczych rzeczy, które są normą w języku C # i Javie. Dynamiczny mechanizm określania zakresu z prostą warstwą konfiguracji na górze może załatwić sprawę. Rozwiązania korporacyjne mogą być nakładane na wierzch przez osoby trzecie.
Waquo
źródło