Come si confrontano i principali framework C # DI / IoC? [chiuso]


308

A rischio di entrare nel territorio della guerra santa, quali sono i punti di forza e di debolezza di questi popolari quadri DI / IoC e si potrebbe facilmente essere considerati i migliori? ..:

  • Ninject
  • Unità
  • Castle.Windsor
  • autofac
  • StructureMap

Esistono altri frame DI / IoC per C # che non ho elencato qui?

Nel contesto del mio caso d'uso, sto costruendo un'app WPF client e un'infrastruttura di servizi WCF / SQL, facilità d'uso (soprattutto in termini di sintassi chiara e concisa), documentazione coerente, buon supporto e prestazioni della community sono tutti fattori importanti nella mia scelta.

Aggiornare:

Le risorse e le domande duplicate citate sembrano non essere aggiornate, può qualcuno con conoscenza di tutti questi framework farsi avanti e fornire una visione reale?

Mi rendo conto che la maggior parte delle opinioni su questo argomento saranno probabilmente di parte, ma spero che qualcuno abbia avuto il tempo di studiare tutti questi quadri e avere almeno un confronto generalmente oggettivo.

Sono abbastanza disposto a fare le mie indagini se ciò non è stato fatto prima, ma ho pensato che fosse qualcosa che almeno alcune persone avevano già fatto.

Secondo aggiornamento:

Se hai esperienza con più di un contenitore DI / IoC, ti preghiamo di classificare e riassumere i pro ei contro di quelli, grazie. Questo non è un esercizio per scoprire tutti i piccoli contenitori oscuri che le persone hanno creato, sto cercando dei confronti tra i quadri popolari (e attivi).


1
Stessa domanda di [Ninject vs Unity per DI] ( stackoverflow.com/questions/1054801/ninject-vs-unity-for-di ), ma potrebbe essere il momento di un follow-up.
Matthew Flaschen,

2
possibile duplicato di [Confronto tra Castle Windsor, Unity e StructureMap] ( stackoverflow.com/questions/2216684/… )
Mauricio Scheffer,

@slomojo: possibile duplicato. stackoverflow.com/questions/4509458/ioc-comparisions-closed . Inoltre c'è un link che mostra la popolarità dell'IoC nella risposta. Date un'occhiata a questo.
Dhinesh,

@chibacity - L'ho usato su ... 4 progetti, i primi due erano davvero basilari, nessun problema, i secondi due, Unity ci ha causato così tanti problemi quando si trattava di iniezione del costruttore, manutenibilità, leggibilità. Abbiamo finito per strappare Unity da entrambi e sostituito con StructureMap, l'iniezione del costruttore era semplicissima, la configurazione era pulita e mantenibile. Nel mio tempo personale ho giocato con AutoFac, ma lo trovo confuso, ho bisogno di un po 'di documentazione per capirlo meglio. Il resto posso solo commentare ciò che ho letto.
Phill

Un problema che abbiamo avuto è stato con SSRS, è stato un errore silenzioso e, passando attraverso il codice, non siamo riusciti a capire perché stesse fallendo, l'eccezione era ambigua. Abbiamo trascorso una settimana a scrivere delle soluzioni per farlo funzionare. Alla fine, quando ci trasferimmo in StructureMap, ci provammo un altro tentativo, e in pochi minuti usando 'ObjectFactory.WhatDoIHave ()' apprendemmo che l'IoC veniva costruito prima che gli assembly fossero caricati in AppDomain, quindi le interfacce non venivano mai registrate con il calcestruzzo tipi.
Phill

Risposte:


225

Mentre una risposta esauriente a questa domanda occupa centinaia di pagine del mio libro , ecco una tabella comparativa rapida su cui sto ancora lavorando:

Una tabella che spiega la differenza tra diversi DIC


40
Ho letto il MEAP del tuo libro e mi chiedevo perché ne hai lasciato fuori Ninject?
Martin Owen,

2
La risposta parziale può essere trovata qui: manning-sandbox.com/thread.jspa?threadID=38943
Mark Seemann

25
@Mark, grazie per questo, si spera che la tua risposta possa includere Ninject (importante, non solo per il nuovo clamore che lo circonda, ma anche per l'uso delle nuove funzionalità del linguaggio.)
ocodo

3
Ninject, sebbene simile ad AutoFac, è usato in molti modi, viene utilizzato dal team NUGET e il contenitore di IOC scaricato più popolare a mani basse. Sono rimasto deluso dal fatto che non fosse presente nel libro di .NET sull'iniezione di dipendenza di Mark. Se c'è una seconda edizione nel modo in cui l'industria appare, si spera che possa entrare nel libro. O mi imbatto in Unity, MEF (non un vero DI), Ninject o StructurMap, devo semplicemente atterrare su un contratto o un concerto remoto che utilizza spring.net o autofac ecc ...
Tom Stickel

2
Unity 3.5 supporta già la registrazione basata su convenzione: nuget.org/packages/Unity/3.5.1404 . Elimina uno svantaggio ;-)
Vladimir Dorokhov,

116

Mi sono imbattuto in un altro confronto delle prestazioni (ultimo aggiornamento 10 aprile 2014). Confronta quanto segue:

Ecco un breve riassunto dal post:

Conclusione

Ninject è sicuramente il contenitore più lento.

MEF, LinFu e Spring.NET sono più veloci di Ninject, ma comunque piuttosto lenti. Seguiranno AutoFac, Catel e Windsor, seguiti da StructureMap, Unity e LightCore. Uno svantaggio di Spring.NET è che può essere configurato solo con XML.

SimpleInjector, Hiro, Funq, Munq e Dynamo offrono le migliori prestazioni, sono estremamente veloci. Provali!

Soprattutto Simple Injector sembra essere una buona scelta. È molto veloce, ha una buona documentazione e supporta anche scenari avanzati come l'intercettazione e decoratori generici.

Puoi anche provare a utilizzare la libreria di selezione dei servizi comuni e, speriamo, provare più opzioni e vedere cosa funziona meglio per te.

Alcune informazioni sulla libreria di selezione dei servizi comuni dal sito:

La libreria fornisce un'astrazione sui contenitori IoC e sui localizzatori di servizi. L'uso della libreria consente a un'applicazione di accedere indirettamente alle funzionalità senza fare affidamento su riferimenti concreti. La speranza è che l'uso di questa libreria, applicazioni e framework di terze parti possano iniziare a sfruttare la posizione IoC / Service senza vincolarsi a un'implementazione specifica.

Aggiornare

13.09.2011: Funq e Munq sono stati aggiunti all'elenco dei concorrenti. Anche i grafici sono stati aggiornati e Spring.NET è stato rimosso a causa delle sue scarse prestazioni.

04.11.2011: "aggiunto Simple Injector , la performance è la migliore di tutti i concorrenti".


(Da seguire il collegamento di confronto) Aggiornato di recente, interessante vedere le differenze di velocità (oltre alla matrice delle caratteristiche di base). Grazie.
lko,

Questo confronto non è così affidabile perché, per quanto ne so, Ninject ha estensioni sia per l'Interception sia per la configurazione XML, mentre il confronto afferma che non lo è.
Daniel,

15
questo è un confronto molto quantitativo. che dire delle funzionalità non prestazionali come la dimensione del file o il numero di dipendenze richieste? Inoltre, sarebbero utili misure soggettive come la qualità della documentazione o l'usabilità. Il mio punto è che ci sono fattori da considerare oltre alla velocità.
FistOfFury

1
Come Jeremy Miller, l'autore di StructureMap ha detto in passato ... parafrasando - Che sicuramente ci sono contenitori IOC più veloci, ma mancano di un set completo di funzionalità.
Tom Stickel,


49

Ho appena letto questo fantastico blog di confronto container .Net DI di Philip Mat.

Fa alcuni approfonditi test comparativi delle prestazioni;

Raccomanda Autofac in quanto è piccolo, veloce e facile da usare ... Sono d'accordo. Sembra che Unity e Ninject siano i più lenti nei suoi test.


5
C'è un aggiornamento al post .Net DI Container Speed ​​Redux : in fondo, c'era un approccio sbagliato adottato per Unity in primo luogo. Con le nuove misurazioni Unity sembra molto meglio.
Volker von Einem,

33

Disclaimer: A partire da inizio 2015, c'è un grande confronto di IoC Container presenta da Jimmy Bogard , ecco un sommario:

Contenitori a confronto:

  • autofac
  • Ninject
  • Iniettore semplice
  • StructureMap
  • Unità
  • Windsor

Lo scenario è questo: ho un'interfaccia, IMediator, in cui posso inviare una singola richiesta / risposta o una notifica a più destinatari:

public interface IMediator 
{ 
    TResponse Send<TResponse>(IRequest<TResponse> request);

    Task<TResponse> SendAsync<TResponse>(IAsyncRequest<TResponse> request);

    void Publish<TNotification>(TNotification notification)
        where TNotification : INotification;

    Task PublishAsync<TNotification>(TNotification notification)
        where TNotification : IAsyncNotification; 
}

Ho quindi creato un set di base di richieste / risposte / notifiche:

public class Ping : IRequest<Pong>
{
    public string Message { get; set; }
}
public class Pong
{
    public string Message { get; set; }
}
public class PingAsync : IAsyncRequest<Pong>
{
    public string Message { get; set; }
}
public class Pinged : INotification { }
public class PingedAsync : IAsyncNotification { }

Ero interessato a guardare alcune cose per quanto riguarda il supporto container per generici:

  • Installazione per generici aperti (registrazione di IRequestHandler <,> facilmente)
  • Installazione per più registrazioni di generici aperti (due o più INotificationHandlers)

Installazione per varianza generica (registrazione dei gestori per INotification di base / creazione di pipeline di richieste) I miei gestori sono piuttosto semplici, vengono semplicemente inviati alla console:

public class PingHandler : IRequestHandler<Ping, Pong> { /* Impl */ }
public class PingAsyncHandler : IAsyncRequestHandler<PingAsync, Pong> { /* Impl */ }

public class PingedHandler : INotificationHandler<Pinged> { /* Impl */ }
public class PingedAlsoHandler : INotificationHandler<Pinged> { /* Impl */ }
public class GenericHandler : INotificationHandler<INotification> { /* Impl */ }

public class PingedAsyncHandler : IAsyncNotificationHandler<PingedAsync> { /* Impl */ }
public class PingedAlsoAsyncHandler : IAsyncNotificationHandler<PingedAsync> { /* Impl */ }

autofac

var builder = new ContainerBuilder();
builder.RegisterSource(new ContravariantRegistrationSource());
builder.RegisterAssemblyTypes(typeof (IMediator).Assembly).AsImplementedInterfaces();
builder.RegisterAssemblyTypes(typeof (Ping).Assembly).AsImplementedInterfaces();
  • Generici aperti: sì, implicitamente
  • Generici multipli aperti: sì, implicitamente
  • Contravarianza generica: sì, esplicitamente

Ninject

var kernel = new StandardKernel();
kernel.Components.Add<IBindingResolver, ContravariantBindingResolver>();
kernel.Bind(scan => scan.FromAssemblyContaining<IMediator>()
    .SelectAllClasses()
    .BindDefaultInterface());
kernel.Bind(scan => scan.FromAssemblyContaining<Ping>()
    .SelectAllClasses()
    .BindAllInterfaces());
kernel.Bind<TextWriter>().ToConstant(Console.Out);
  • Generici aperti: sì, implicitamente
  • Generici multipli aperti: sì, implicitamente
  • Contravarianza generica: sì, con estensioni create dall'utente

Iniettore semplice

var container = new Container();
var assemblies = GetAssemblies().ToArray();
container.Register<IMediator, Mediator>();
container.Register(typeof(IRequestHandler<,>), assemblies);
container.Register(typeof(IAsyncRequestHandler<,>), assemblies);
container.RegisterCollection(typeof(INotificationHandler<>), assemblies);
container.RegisterCollection(typeof(IAsyncNotificationHandler<>), assemblies);
  • Generici aperti: sì, esplicitamente
  • Generici multipli aperti: sì, esplicitamente
  • Contravarianza generica: sì, implicitamente (con aggiornamento 3.0)

StructureMap

var container = new Container(cfg =>
{
    cfg.Scan(scanner =>
    {
        scanner.AssemblyContainingType<Ping>();
        scanner.AssemblyContainingType<IMediator>();
        scanner.WithDefaultConventions();
        scanner.AddAllTypesOf(typeof(IRequestHandler<,>));
        scanner.AddAllTypesOf(typeof(IAsyncRequestHandler<,>));
        scanner.AddAllTypesOf(typeof(INotificationHandler<>));
        scanner.AddAllTypesOf(typeof(IAsyncNotificationHandler<>));
    });
});
  • Generici aperti: sì, esplicitamente
  • Generici multipli aperti: sì, esplicitamente
  • Contravarianza generica: sì, implicitamente

Unità

container.RegisterTypes(AllClasses.FromAssemblies(typeof(Ping).Assembly),
   WithMappings.FromAllInterfaces,
   GetName,
   GetLifetimeManager);

/* later down */

static bool IsNotificationHandler(Type type)
{
    return type.GetInterfaces().Any(x => x.IsGenericType && (x.GetGenericTypeDefinition() == typeof(INotificationHandler<>) || x.GetGenericTypeDefinition() == typeof(IAsyncNotificationHandler<>)));
}

static LifetimeManager GetLifetimeManager(Type type)
{
    return IsNotificationHandler(type) ? new ContainerControlledLifetimeManager() : null;
}

static string GetName(Type type)
{
    return IsNotificationHandler(type) ? string.Format("HandlerFor" + type.Name) : string.Empty;
}
  • Generici aperti: sì, implicitamente
  • Generici multipli aperti: sì, con estensione creata dall'utente
  • Contravarianza generica: derp

Windsor

var container = new WindsorContainer();
container.Register(Classes.FromAssemblyContaining<IMediator>().Pick().WithServiceAllInterfaces());
container.Register(Classes.FromAssemblyContaining<Ping>().Pick().WithServiceAllInterfaces());
container.Kernel.AddHandlersFilter(new ContravariantFilter());
  • Generici aperti: sì, implicitamente
  • Generici multipli aperti: sì, implicitamente
  • Contravarianza generica: sì, con estensione creata dall'utente

Eccellente! A proposito, il sommario sopra mancava a Windsor, ma è disponibile nell'articolo originale di Jimmy.
Louis,

Wow nessuno lo ha avvertito prima (: ho aggiunto windsor, grazie @Louis
stratovarius

21

In realtà ci sono tonnellate di framework IoC. Sembra che ogni programmatore cerchi di scriverne uno ad un certo punto della sua carriera. Forse non per pubblicarlo, ma per imparare i meccanismi interni.

Personalmente preferisco l'autofac poiché è abbastanza flessibile e ha una sintassi adatta a me (anche se odio davvero che tutti i metodi di registrazione siano metodi di estensione).

Alcuni altri framework:


Ciao @abatishchev! :) ... l'idea originale era quella di assicurarsi che i metodi di terze parti e integrati fossero sullo stesso piano; molti metodi di "registrazione" devono essere spediti separatamente (ad es. RegisterControllers()per MVC), quindi ho pensato che valesse la pena progettare in quel caso. (Questo è stato progettato più di 5 anni fa.)
Nicholas Blumhardt l'

1
@NicholasBlumhardt: Ciao! :) Ci scusiamo per la risposta tardiva, la notifica è andata persa tra gli altri. In realtà un tale interesse per coerenza ha senso per me. Come pensi ora, come lo progetteresti?
abatishchev,

@abatishchev Non sono d'accordo con jgauffin. I metodi di estensione non vengono chiusi per estensione, ma come estensione. Scrivi il nucleo del tuo framework che può fare tutto ciò che dovrebbe e con i metodi di estensione fornisci alcune funzionalità aggiuntive, forse alcuni helper predefiniti, ma chiunque altro è libero di scrivere le proprie estensioni. Direi che se il tuo framework accetta metodi di estensione per estenderlo, allora è un buon framework.
t3chb0t,

6

Bene, dopo aver cercato il miglior confronto che ho trovato finora è:

È stato un sondaggio condotto nel marzo 2010.

Un punto di interesse per me è che le persone che hanno utilizzato un framework DI / IoC e lo hanno apprezzato / non apprezzato, StructureMap sembrano emergere in cima.

Sempre dal sondaggio, sembra che Castle.Windsor e StructureMap sembrano essere i più favoriti.

È interessante notare che Unity e Spring.Net sembrano essere le opzioni popolari a cui generalmente non . (Stavo considerando Unity per pigrizia (e badge / supporto Microsoft), ma ora esaminerò più da vicino Castle Windsor e StructureMap.)

Naturalmente questo probabilmente (?) Non si applica a Unity 2.0 che è stato rilasciato a maggio 2010.

Speriamo che qualcun altro possa fornire un confronto basato sull'esperienza diretta.


2
L'unità è abbastanza buona. Copre la maggior parte di ciò di cui si ha bisogno, anche se alcune persone si lamentano del fatto che non risolva le dipendenze circolari. Lo adoro. Faccio tutto ciò di cui ho bisogno.
Dmitri Nesteruk,

Molti sviluppatori stanno usando Castle.Windsor senza nemmeno saperlo. È l'Ioc predefinito per NHibernate . (Almeno con FluentNHibernate ho scaricato ieri). Ho anche visto un'implementazione di NHibernate che utilizza LinFu nstead
k3b

5

Vedere per un confronto di net-ioc-framework su codice google inclusi linfu e spring.net che non sono nella tua lista mentre scrivo questo testo.

Ho lavorato con spring.net: ha molte funzionalità (aop, librerie, docu, ...) e c'è molta esperienza con esso nel dotnet e nel mondo java. Le funzionalità sono modularizzate, quindi non devi prendere tutte le funzionalità. Le funzionalità sono astrazioni di problemi comuni come astrazione di database, astrazione di registrazione. tuttavia è difficile eseguire ed eseguire il debug della configurazione IoC.

Da quello che ho letto finora: se dovessi scegliere per un progetto piccolo o medio userei ninject poiché la configurazione di ioc è fatta e debuggabile in c #. Ma non ho ancora lavorato con esso. per sistemi modulari di grandi dimensioni rimarrei con spring.net a causa delle librerie di astrazione.

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.