Come si può integrare l'iniezione di dipendenza nella lingua? [chiuso]


10

Ho pensato un po 'su come l'iniezione di dipendenza potesse essere meglio integrata direttamente in un linguaggio simile a C #. Ho trovato una potenziale soluzione su cui vorrei sentire la tua opinione. Non ho usato molti framework di iniezione di dipendenza, quindi potrebbe esserci qualcosa che sto trascurando

Ad ogni modo, l'idea è quella di poter dichiarare le proprietà "iniettabili" usando una parola chiave. Quando un oggetto viene istanziato e quella proprietà non è inizializzata tramite il costruttore o l'inizializzatore di oggetti, richiede un'istanza di quel tipo di proprietà da un servizio globale.

Allo stesso modo si registrano gestori per tipi diversi a quel servizio in modo da poter istanziare il tipo di proprietà iniettato.

L'aspetto positivo dell'utilizzo di questo tipo di architettura IMO è che è abbastanza flessibile e facile da usare. Il rovescio della medaglia è che potrebbe esserci un certo sovraccarico nel fare il richiamo al singleton ogni volta che si avvia una classe che ha l'iniezione.

Inoltre, questo è solo un problema per le classi che vengono istanziate frequentemente in una soluzione ad alte prestazioni, quindi non dovrebbe essere un grosso problema. Forse potresti usare una specie di fabbrica in quei casi.

Pensiero, problemi, domande, idee migliori?

Codice

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

Potresti dare un esempio di pseudo codice per quelli di noi che non hanno familiarità con DI? PS. Forse puoi rispondere anche alla mia domanda su DI? :)
Steven

2
Non sono sicuro di averlo. Puoi ottenere tutto ciò con un contenitore DI globale e un attributo '[Injectable]' invece di una parola chiave, giusto?
Nikie,

Ciao, ho provato a scrivere un po 'di DI sulla tua domanda, non sono sicuro che risponda però
Homde

nikie: Sì certo, immagino che potresti implementare il meccanismo reale in diversi modi, sono più interessato se la logica di base è
valida

Quindi, cosa c'è di diverso tra questo e l'IoC diverso dalla tua parola chiave extra?
Matthew Whited,

Risposte:


7

Ci sono cose che appartengono alle lingue e cose che non lo fanno. Molto tempo fa C ha riconosciuto che IO non apparteneva alla lingua perché è esterno al modello di calcolo e può essere implementato con librerie di funzioni.

L'iniezione di dipendenza è così. È esterno al linguaggio e può essere implementato con framework appropriati.

Uno dei problemi con le lingue moderne è che provano a fare troppo. Alla fine quelle lingue collassano sotto il loro stesso peso mentre i programmatori fuggono verso lingue più semplici.


Sono d'accordo in teoria, non puoi avere una lingua in cui ogni funzione è una caratteristica della lingua senza che sia gonfiata. Tuttavia c'è sempre spazio per nuove astrazioni più elevate che ci aiutano a scrivere codice migliore. Forse l'iniezione di dipendenza in sé non è il problema che deve essere risolto, ma il problema che affronta, vale a dire un modo per rendere più facile per noi ridurre le dipendenze. Questo potrebbe non essere il modo migliore per farlo :)
Homde

5

Non è necessario

Una delle cose che mi piacciono di più dei migliori framework DI che ho usato è che il codice di configurazione di livello superiore è l'unica parte del tuo codice che deve conoscere DI. Il cablaggio automatico viene eseguito a livello di contenitore e di configurazione / "caricamento del modulo" e il codice dell'applicazione può essere completamente ignaro.

Questo significa nessun attributo, nessuna stringa magica, nessuna convenzione. Ogni pezzo di codice sa solo che accetta codice nel suo costruttore (/ proprietà / metodi), e questo è tutto.

Con un design del genere non è necessario modificare affatto la lingua per supportare l'iniezione di dipendenza.

È potenzialmente pericoloso

La cosa che temo di più di un sistema di iniezione di dipendenza integrato nel linguaggio è che potrebbe sollevare una barriera contro qualsiasi altra implementazione, ma probabilmente si dipingerebbe in un angolo in qualche aspetto.

Alcuni modi in cui potrebbe dipingersi in un angolo:

  • Supporta solo la configurazione basata su XML o solo la configurazione basata su codice
  • Non essere in grado di supportare in modo pulito il modello di progettazione di fabbrica (non solo componenti transitori: componenti generati dal runtime)
  • In qualche modo cambiando il mio codice così sono stato costretto a usare l'iniezione delle dipendenze e non potevo semplicemente istanziare la mia classe per i test unitari
  • Non supporta cicli di vita personalizzati
  • Non essere estensibile
  • Non essere sostituibile nei casi in cui ho bisogno di una maggiore personalizzazione
  • Essere rotti in un modo che non capiamo ancora, perché noi utenti .Net non usiamo DI da abbastanza tempo per conoscere le insidie

4

Hai visto il Managed Extensibility Framework fornito con .NET 4? Ecco un articolo che ho scritto con alcuni esempi. Fondamentalmente è una forma di iniezione di dipendenza integrata in .NET, con le funzionalità aggiunte di rilevabilità di runtime.

Le iniezioni di proprietà si presentano così:

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

Le iniezioni del costruttore si presentano così:

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

È possibile importare campi, importare facoltativamente, importare raccolte di servizi, inclusa l'importazione lenta con metadati in modo da poter cercare un servizio appropriato da istanziare. Puoi anche reimportare in fase di runtime per cercare nuove estensioni.


Mentre MEF è davvero interessante per i plugin, non penso che mi piacerebbe usarlo come un meccanismo DI generale
Homde

1
@MKO - Puoi approfondire cosa manca? Sono a conoscenza di tutti gli articoli in cui Glenn Block corre per rassicurare le persone sul fatto che MEF non è disposto a sostituire tutti i framework DI, ma se si guardano i dettagli, è ovvio che è più una dichiarazione politica che altro. Tuttavia, se puoi fornire un buon elenco di funzionalità che MEF non ha rispetto ad altri framework DI, ciò aiuterà le persone a prendere una decisione informata. Inoltre, la domanda riguarda i framework DI in C # e MEF è chiaramente un contenitore DI nel framework .NET.
Scott Whitlock,

2
  1. Non descrivi davvero il meccanismo di configurazione, che IMHO è la parte difficile. Come si fa in modo che tutto il codice in esecuzione in un thread utilizzi la connessione DB A e tutto il codice nell'altra connessione thread B? Come si blocca l'iniezione di una determinata risorsa, poiché l'utente attualmente connesso non è autorizzato ad accedervi?
  2. Non usare un iniettore globale. Non usare nulla di globale, o potresti anche usare variabili globali. No, l'uso di OOP-speak come singleton o "statico" anziché globale non cambia la loro natura globale.
  3. Considera un contenitore con ambito dinamico. Mentre lo scoping lessicale ha giustamente vinto contro lo scoping dinamico, credo che l'ambito dinamico possa sostituire con precisione l'ambito globale. L'ereditarietà differenziale sarebbe una buona implementazione (come nell'ereditarietà basata sui prototipi).
  4. Credo che un meccanismo DI obbligato al linguaggio dovrebbe essere davvero semplice, nessuna di quelle cose aziendali che è la norma in C # e Java. Un meccanismo di scoping dinamico con un semplice livello di configurazione in alto potrebbe fare il trucco. Le soluzioni aziendali potrebbero essere sovrapposte a terzi.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.