Dipendenze mancanti al momento della compilazione con IOC

4

Grazie al mio nuovo lavoro, ho scoperto di recente l'inversione del principio del controllo del design (con il castello di windsor in C #).

Mi piace davvero usarlo ma qualcosa mi infastidisce. Per quanto mi riguarda, la buona parte delle lingue strongmente tipizzate è il fatto che puoi vedere errori in fase di compilazione e evitare che la tua app si blocchi casualmente durante l'esecuzione solo perché hai fatto un refuso su un nome di dipendenza. Ma l'inversione del controllo annulla tutto, se hai una dipendenza mancante non ci saranno problemi in fase di compilazione.

C'è un modo per dire al compilatore di verificare se le dipendenze esistono realmente?

    
posta Gatoyu 30.05.2016 - 17:41
fonte

3 risposte

2

Soluzione alternativa:
Se il tuo contenitore è in grado di convalidare la propria configurazione, puoi scrivere un test di integrazione per questo.

Questo non è un vero controllo del tempo di compilazione, ma se fa parte della tua suite di test, noterai ancora le dipendenze mancanti rapidamente.
Ovviamente funziona solo quando tutte le tue dipendenze sono conosciute al momento della compilazione.

Ecco un esempio di un mio recente progetto, che utilizza SimpleInjector .
SimpleInjector ha un metodo Verify() , che tenta di risolvere tutte le dipendenze registrate .

Sto usando SimpleInjector in questo modo:

public class Bootstrapper
{
    public static Container BuildContainer()
    {
        var container = new Container();
        container.Register<IFoo, Foo>();
        container.Register<IBar, Bar>();
        // etc.

        container.Verify();

        return container;
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        var container = Bootstrapper.BuildContainer();

        container.GetInstance<IFoo>().Run();
    }
}

Verify genererà un'eccezione quando qualcosa va storto, quindi l'app si arresterà in modo anomalo in fase di runtime.

Per verificarlo mentre eseguivo la mia suite di test, ho scritto il seguente test (sintassi xUnit.net):

public class BootstrapperTests
{
    [Fact]
    public void DependenciesWereResolved()
    {
        bool error = false;

        try
        {
            var container = Bootstrapper.BuildContainer();   
        }
        catch (InvalidOperationException)
        {
            error = true;
        }

        Assert.False(error);
    }
}

Nota: xUnit.net non ha nulla come Assert.DidNotThrow<Exception> , ecco perché ho bisogno di intercettare l'eccezione e impostare la variabile error .

    
risposta data 30.05.2016 - 20:04
fonte
5

Se preferisci mantenere il controllo della compilazione del tempo, non c'è assolutamente alcun motivo per cui non potresti costruire le tue dipendenze usando la cosiddetta "iniezione da pover'uomo" - vale a dire, costruendo l'albero delle dipendenze da solo chiamando i costruttori. Sebbene i contenitori DI siano un potente strumento in grado di supportare Inversion Of Control nel codice, non sono l'unico modo per invertire le dipendenze. Il punto saliente qui è che ogni unità di codice si basa ancora su interfacce astratte che vengono iniettate al momento della risoluzione, e non su altre classi concrete.

Se segui questa strada, potresti comunque voler estrarre la rotta della risoluzione delle dipendenze. Vale a dire, invece di rendere lo stack dell'applicazione responsabile dei controller in un'applicazione MVC, sarebbe preferibile creare l'applicazione e il livello dati in un factory esterno e iniettare tali dipendenze nei controller come richiesto. In questo modo, hai un componente di codice che potrebbe potenzialmente gestire la durata e la costruzione dei tuoi oggetti.

Naturalmente, a questo punto, stai ironicamente lavorando verso una sorta di contenitore IoC di base, ma è un contenitore IoC altamente specifico per la tua applicazione. Per un'applicazione più semplice, questo potrebbe essere preferibile a un contenitore DI in piena regola, con registrazione per convenzione e tutti i campanelli e fischietti.

    
risposta data 30.05.2016 - 18:18
fonte
3

Non per la maggior parte dei contenitori IOC.

Voglio dire, il loro solito scopo è quello di raccogliere plugin e legare tutto insieme. Sconfigge piuttosto lo scopo se tutti i plugin sono noti al momento della compilazione.

E spostare gli errori del tempo di compilazione in errori di runtime è uno dei principali svantaggi di queste cose. Sono decisamente non universalmente buoni.

    
risposta data 30.05.2016 - 17:54
fonte

Leggi altre domande sui tag