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

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

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

Ci sono altri DI / IoC Framework 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 syntax chiara e concisa), documentazione coerente, buon supporto della comunità e prestazioni sono tutti fattori importanti nella mia scelta

Aggiornare:

Le risorse e le domande duplicate citate sembrano essere obsolete, qualcuno con conoscenza di tutti questi quadri può farsi avanti e fornire qualche intuizione reale?

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

Sono abbastanza disposto a fare le mie indagini se questo 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, per favore classifica e riassumi i pro e i contro di quelli, grazie. Questo non è un esercizio per scoprire tutti i piccoli contenitori oscuri che le persone hanno fatto, sto cercando dei confronti tra le strutture popolari (e attive).

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

Una tabella che spiega la differenza tra diversi DIC

Mi sono imbattuto in un altro confronto dei risultati (ultimo aggiornamento il 10 aprile 2014). Confronta i seguenti:

  • autofac
  • LightCore (il sito è tedesco)
  • Linfu
  • Ninject
  • Petite
  • Injector semplice (il più veloce di tutti i concorrenti)
  • Spring.NET
  • StructureMap
  • Unità
  • Windsor
  • Hiro

Ecco un breve riassunto dal post:

Conclusione

Ninject è sicuramente il contenitore più lento.

MEF, LinFu e Spring.NET sono più veloci di Ninject, ma ancora piuttosto lenti. AutoFac, Catel e Windsor vengono dopo, seguito 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!

Iniettore particolarmente semplice sembra essere una buona scelta. È molto veloce, ha una buona documentazione e supporta anche scenari avanzati come l’intercettazione e i decoratori generici.

Puoi anche provare a usare la Common Selector Library e sperare di provare più opzioni e vedere cosa funziona meglio per te.

Alcune informazioni su Common Service Selector Library dal sito:

La libreria fornisce un’astrazione su contenitori IoC e localizzatori di servizi. L’utilizzo della libreria consente a un’applicazione di accedere indirettamente alle funzionalità senza fare affidamento su riferimenti rigidi. La speranza è che usando questa libreria, le applicazioni e i framework di terze parti possano iniziare a sfruttare IoC / Service Location senza limitarsi 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 scarse prestazioni.

04.11.2011: “Aggiunto Simple Injector , la performance è la migliore di tutti i concorrenti”.

Basta leggere questo fantastico blog di confronto dei contenitori .Net di Philip Mat.

Effettua alcuni accurati test di confronto delle prestazioni;

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

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.

Disclaimer: all’inizio del 2015, c’è un ottimo confronto tra le caratteristiche del contenitore IoC di Jimmy Bogard , ecco un riassunto:

Contenitori confrontati:

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

Lo scenario è questo: ho un’interfaccia, IMediator, nella quale posso inviare una singola richiesta / risposta o una notifica a più destinatari:

public interface IMediator { TResponse Send(IRequest request); Task SendAsync(IAsyncRequest request); void Publish(TNotification notification) where TNotification : INotification; Task PublishAsync(TNotification notification) where TNotification : IAsyncNotification; } 

Ho quindi creato una serie di richieste / risposte / notifiche:

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

Mi interessava osservare alcune cose riguardo al supporto dei contenitori per i generici:

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

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

 public class PingHandler : IRequestHandler { /* Impl */ } public class PingAsyncHandler : IAsyncRequestHandler { /* Impl */ } public class PingedHandler : INotificationHandler { /* Impl */ } public class PingedAlsoHandler : INotificationHandler { /* Impl */ } public class GenericHandler : INotificationHandler { /* Impl */ } public class PingedAsyncHandler : IAsyncNotificationHandler { /* Impl */ } public class PingedAlsoAsyncHandler : IAsyncNotificationHandler { /* 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 aperti multipli: sì, implicitamente
  • Contravarianza generica: sì, esplicitamente

Ninject

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

Iniettore semplice

 var container = new Container(); var assemblies = GetAssemblies().ToArray(); container.Register(); 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 aperti multipli: sì, esplicitamente
  • Contravarianza generica: sì, implicitamente (con aggiornamento 3.0)

StructureMap

 var container = new Container(cfg => { cfg.Scan(scanner => { scanner.AssemblyContainingType(); scanner.AssemblyContainingType(); scanner.WithDefaultConventions(); scanner.AddAllTypesOf(typeof(IRequestHandler<,>)); scanner.AddAllTypesOf(typeof(IAsyncRequestHandler<,>)); scanner.AddAllTypesOf(typeof(INotificationHandler<>)); scanner.AddAllTypesOf(typeof(IAsyncNotificationHandler<>)); }); }); 
  • Generici aperti: sì, esplicitamente
  • Generici aperti multipli: 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 aperti multipli: sì, con estensione creata dall’utente
  • Contravarianza generica: derp

Windsor

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

In realtà ci sono tonnellate di strutture IoC. Sembra che ogni programmatore cerchi di scriverne uno ad un certo punto della propria carriera. Forse non pubblicarlo, ma per imparare il funzionamento interno.

Personalmente preferisco autofac perché è abbastanza flessibile e ha una syntax che mi si addice (anche se odio davvero che tutti i metodi di registrazione sono metodi di estensione).

Alcuni altri quadri:

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

Era un sondaggio fatto a marzo 2010.

Un punto di interesse per me è che le persone che hanno utilizzato un DI / IoC Framework e l’hanno apprezzato / non l’hanno apprezzato, StructureMap sembra uscito in cima.

Anche 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 che generalmente non piacciono. (Stavo considerando Unity per pigrizia (e badge / supporto Microsoft), ma guarderò più da vicino Castle Windsor e StructureMap ora.)

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

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

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

Ho lavorato con spring.net: ha molte caratteristiche (aop, librerie, docu, …) e c’è molta esperienza con esso nel dotnet e nel mondo java. Le funzionalità sono modularizzate in modo da non dover prendere tutte le funzionalità. Le funzionalità sono astrazioni di problemi comuni come databaseabstraction, loggingabstraction. tuttavia è difficile da fare ed eseguire il debug della configurazione IoC.

Da quello che ho letto finora: Se dovessi scegliereh per un progetto piccolo o medio, userei ninject da quando la configurazione di ioc è terminata e debuggibile in c #. Ma non ho ancora lavorato con questo. per un grande sistema modulare starei con spring.net a causa delle librerie di astrazione.