Wie vergleichen sich die wichtigsten C # DI / IoC-Frameworks? [geschlossen]

308

Was sind die Stärken und Schwächen dieser beliebten DI / IoC-Frameworks und könnte man sie leicht als die besten bezeichnen? ..:

  • Ninject
  • Einheit
  • Castle.Windsor
  • Autofac
  • StructureMap

Gibt es andere DI / IoC-Frameworks für C #, die ich hier nicht aufgelistet habe?

Im Kontext meines Anwendungsfalls erstelle ich eine Client-WPF-App und eine WCF / SQL-Dienstinfrastruktur. Benutzerfreundlichkeit (insbesondere in Bezug auf klare und präzise Syntax), konsistente Dokumentation, gute Community-Unterstützung und Leistung sind wichtige Faktoren in meiner Wahl.

Aktualisieren:

Die genannten Ressourcen und doppelten Fragen scheinen veraltet zu sein. Kann sich jemand mit Kenntnissen über all diese Frameworks melden und echte Einblicke gewähren?

Mir ist klar, dass die meisten Meinungen zu diesem Thema wahrscheinlich voreingenommen sind, aber ich hoffe, dass sich jemand die Zeit genommen hat, all diese Rahmenbedingungen zu studieren und zumindest einen allgemein objektiven Vergleich zu haben.

Ich bin durchaus bereit, meine eigenen Untersuchungen durchzuführen, wenn dies noch nicht geschehen ist, aber ich nahm an, dass dies etwas war, was zumindest einige Leute bereits getan hatten.

Zweites Update:

Wenn Sie Erfahrung mit mehr als einem DI / IoC-Container haben, ordnen Sie bitte die Vor- und Nachteile dieser Container ein und fassen Sie sie zusammen. Vielen Dank. Dies ist keine Übung, um all die obskuren kleinen Container zu entdecken, die die Leute gemacht haben. Ich suche nach Vergleichen zwischen den beliebten (und aktiven) Frameworks.

ocodo
quelle
1
Dieselbe Frage wie [Ninject vs Unity für DI] ( stackoverflow.com/questions/1054801/ninject-vs-unity-for-di ), aber es kann Zeit für ein Follow-up sein.
Matthew Flaschen
2
Mögliches Duplikat von [Vergleich von Castle Windsor, Unity und StructureMap] ( stackoverflow.com/questions/2216684/… )
Mauricio Scheffer
@slomojo: Mögliches Duplikat. stackoverflow.com/questions/4509458/ioc-comparisions-closed . Es gibt auch einen Link, der die Popularität der IoCs in der Antwort zeigt. Schau es dir an.
Dhinesh
@chibacity - Ich habe es für ... 4 Projekte verwendet, die ersten beiden waren wirklich einfach, keine Probleme, die zweiten beiden, Unity verursachte uns so viele Probleme, wenn es um Konstruktorinjektion, Wartbarkeit und Lesbarkeit ging. Am Ende haben wir Unity aus beiden herausgerissen und durch StructureMap ersetzt. Die Konstruktorinjektion war kinderleicht, die Konfiguration war sauber und wartbar. In meiner persönlichen Zeit habe ich mit AutoFac gespielt, aber ich finde es fummelig, brauche eine Dokumentation, um es besser zu verstehen. Den Rest kann ich nur kommentieren, was ich gelesen habe.
Phill
Ein Problem, das wir hatten, war mit SSRS, es schlug stillschweigend fehl und beim Durchlaufen des Codes konnten wir nicht herausfinden, warum es fehlschlug. Die Ausnahme war nicht eindeutig. Wir haben eine Woche damit verbracht, Workarounds zu schreiben, damit es funktioniert. Als wir schließlich zu StructureMap wechselten, hatten wir einen weiteren Versuch und innerhalb von Minuten erfuhren wir mit 'ObjectFactory.WhatDoIHave ()', dass die IoC erstellt wurde, bevor die Baugruppen in die AppDomain geladen wurden, sodass die Schnittstellen nie mit dem Beton registriert wurden Typen.
Phill

Antworten:

225

Während eine umfassende Antwort auf diese Frage Hunderte von Seiten meines Buches einnimmt , ist hier eine kurze Vergleichstabelle, an der ich noch arbeite:

Eine Tabelle, in der der Unterschied zwischen mehreren DICs erläutert wird

Mark Seemann
quelle
40
Ich habe den MEAP Ihres Buches gelesen und mich gefragt, warum Sie Ninject davon ausgeschlossen haben.
Martin Owen
2
Eine teilweise Antwort finden Sie hier: manning-sandbox.com/thread.jspa?threadID=38943
Mark Seemann
25
@ Mark, danke dafür, hoffentlich könnte Ihre Antwort Ninject enthalten (wichtig, nicht nur wegen des neuen Hype, der es umgibt, sondern auch wegen der Verwendung neuer
Sprachfunktionen
3
Ninject ähnelt AutoFac in vielerlei Hinsicht, wird jedoch vom NUGET-Team verwendet und der beliebteste heruntergeladene IOC-Container ist zweifellos. Ich war enttäuscht, dass es nicht in Marks Dependency Injection in .NET-Buch war. Wenn es eine zweite Ausgabe gibt, wie die Branche aussieht, würde sie es hoffentlich in das Buch schaffen. Entweder stoße ich auf Unity, MEF (kein echter DI), Ninject oder StructurMap. Ich muss einfach noch auf einem Vertrag oder einem Remote-Gig landen, der spring.net oder autofac usw. verwendet.
Tom Stickel
2
Unity 3.5 unterstützt bereits die auf Konventionen basierende Registrierung: nuget.org/packages/Unity/3.5.1404 . Einen Nachteil
beseitigen ;-)
116

Ich bin auf einen weiteren Leistungsvergleich gestoßen (letztes Update 10. April 2014). Es vergleicht Folgendes:

Hier ist eine kurze Zusammenfassung aus dem Beitrag:

Fazit

Ninject ist definitiv der langsamste Container.

MEF, LinFu und Spring.NET sind schneller als Ninject, aber immer noch ziemlich langsam. Als nächstes folgen AutoFac, Catel und Windsor, gefolgt von StructureMap, Unity und LightCore. Ein Nachteil von Spring.NET ist, dass es nur mit XML konfiguriert werden kann.

SimpleInjector, Hiro, Funq, Munq und Dynamo bieten die beste Leistung, sie sind extrem schnell. Probieren Sie es aus!

Besonders Simple Injector scheint eine gute Wahl zu sein. Es ist sehr schnell, hat eine gute Dokumentation und unterstützt auch fortgeschrittene Szenarien wie Abfangen und generische Dekorateure.

Sie können auch versuchen, die Common Service Selector Library zu verwenden, und hoffentlich mehrere Optionen ausprobieren, um herauszufinden, was für Sie am besten funktioniert.

Einige Informationen zur Common Service Selector Library auf der Website:

Die Bibliothek bietet eine Abstraktion über IoC-Container und Service Locators. Durch die Verwendung der Bibliothek kann eine Anwendung indirekt auf die Funktionen zugreifen, ohne auf harte Referenzen angewiesen zu sein. Die Hoffnung ist, dass mit dieser Bibliothek Anwendungen und Frameworks von Drittanbietern beginnen können, IoC / Service Location zu nutzen, ohne sich an eine bestimmte Implementierung zu binden.

Aktualisieren

13.09.2011: Funq und Munq wurden der Teilnehmerliste hinzugefügt. Die Diagramme wurden ebenfalls aktualisiert und Spring.NET wurde aufgrund seiner schlechten Leistung entfernt.

04.11.2011: " Simple Injector hinzugefügt , die Leistung ist die beste aller Teilnehmer".

Pranav Shah
quelle
(Aus dem Vergleichslink folgen) Kürzlich aktualisiert, interessant, um die Geschwindigkeitsunterschiede (plus die Matrix der Grundfunktionen) zu sehen. Vielen Dank.
lko
Dieser Vergleich ist nicht so zuverlässig, da Ninject meines Wissens Erweiterungen sowohl für die Interception- als auch für die XML-Konfiguration hat, während der Vergleich dies nicht angibt.
Daniel
15
Dies ist ein sehr quantitativer Vergleich. Was ist mit nicht leistungsfähigen Funktionen wie Dateigröße oder Anzahl der erforderlichen Abhängigkeiten? Darüber hinaus wären subjektive Maßnahmen wie Dokumentationsqualität oder Benutzerfreundlichkeit hilfreich. Mein Punkt ist, dass es andere Faktoren als die Geschwindigkeit gibt, die berücksichtigt werden müssen.
FistOfFury
1
Wie Jeremy Miller hat der Autor von StructureMap in der Vergangenheit gesagt ... paraphrasieren - Dass es sicher schnellere IOC-Container gibt, aber ihnen fehlen alle Funktionen.
Tom Stickel
Überprüfen Sie dies: iocservicestack.net
Rajesh Jinaga
49

Lesen Sie einfach diesen großartigen .Net DI-Container-Vergleichsblog von Philip Mat.

Er führt einige gründliche Leistungsvergleichstests durch;

Er empfiehlt Autofac, da es klein, schnell und einfach zu bedienen ist ... Ich stimme zu. Es scheint, dass Unity und Ninject die langsamsten in seinen Tests sind.

brodie
quelle
5
Es gibt ein Update für den Beitrag .Net DI Container Speed ​​Redux : Unter dem Strich wurde für Unity in erster Linie ein falscher Ansatz gewählt. Mit den neuen Messungen sieht Unity viel besser aus.
Volker von Einem
33

Haftungsausschluss: Ab Anfang 2015 gibt es einen großartigen Vergleich der IoC Container- Funktionen von Jimmy Bogard . Hier eine Zusammenfassung:

Vergleichsbehälter:

  • Autofac
  • Ninject
  • Einfacher Injektor
  • StructureMap
  • Einheit
  • Windsor

Das Szenario lautet wie folgt: Ich habe eine Schnittstelle, IMediator, über die ich eine einzelne Anfrage / Antwort oder eine Benachrichtigung an mehrere Empfänger senden kann:

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

Ich habe dann einen Basissatz von Anfragen / Antworten / Benachrichtigungen erstellt:

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 { }

Ich war daran interessiert, einige Dinge in Bezug auf die Containerunterstützung für Generika zu untersuchen:

  • Setup für offene Generika (einfache Registrierung von IRequestHandler <,>)
  • Einrichtung für mehrere Registrierungen offener Generika (zwei oder mehr INotificationHandler)

Setup für generische Varianz (Registrieren von Handlern für Base INotification / Erstellen von Anforderungspipelines) Meine Handler sind ziemlich einfach, sie geben nur auf der Konsole aus:

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();
  • Offene Generika: ja, implizit
  • Mehrere offene Generika: Ja, implizit
  • Generische Kontravarianz: Ja, explizit

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);
  • Offene Generika: ja, implizit
  • Mehrere offene Generika: Ja, implizit
  • Generische Kontravarianz: Ja, mit benutzerdefinierten Erweiterungen

Einfacher Injektor

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);
  • Offene Generika: Ja, explizit
  • Mehrere offene Generika: Ja, explizit
  • Generische Kontravarianz: Ja, implizit (mit Update 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<>));
    });
});
  • Offene Generika: Ja, explizit
  • Mehrere offene Generika: Ja, explizit
  • Generische Kontravarianz: Ja, implizit

Einheit

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;
}
  • Offene Generika: ja, implizit
  • Mehrere offene Generika: Ja, mit benutzerdefinierter Erweiterung
  • Generische Kontravarianz: 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());
  • Offene Generika: ja, implizit
  • Mehrere offene Generika: Ja, implizit
  • Generische Kontravarianz: Ja, mit benutzerdefinierter Erweiterung
Stratovarius
quelle
Ausgezeichnet! Übrigens hat die obige Zusammenfassung Windsor verpasst, aber sie ist im Originalartikel von Jimmy verfügbar.
Louis
Wow, niemand hat vorher davor gewarnt (: Ich habe Windsor hinzugefügt, danke @Louis
Stratovarius
21

Tatsächlich gibt es Tonnen von IoC-Frameworks. Es scheint, als würde jeder Programmierer irgendwann in seiner Karriere versuchen, einen zu schreiben. Vielleicht nicht, um es zu veröffentlichen, sondern um das Innenleben zu lernen.

Ich persönlich bevorzuge Autofac, da es sehr flexibel ist und eine Syntax hat, die zu mir passt (obwohl ich es wirklich hasse, dass alle Registermethoden Erweiterungsmethoden sind).

Einige andere Frameworks:

jgauffin
quelle
Hallo @abatishchev! :) ... die ursprüngliche Idee war, sicherzustellen, dass Drittanbieter- und integrierte Methoden auf dem gleichen Fundament stehen; Viele "Register" -Methoden müssen separat ausgeliefert werden (z. B. RegisterControllers()für MVC), daher hielt ich das Entwerfen für diesen Fall für sinnvoll. (Dies wurde vor mehr als 5 Jahren entworfen.)
Nicholas Blumhardt
1
@NicholasBlumhardt: Hi! :) Entschuldigung für die verspätete Antwort, die Benachrichtigung ging unter den anderen verloren. Eigentlich macht ein solcher Grund der Konsistenz für mich Sinn. Wie denkst du jetzt, wie würdest du es gestalten?
Abatishchev
@abatishchev Ich stimme jgauffin nicht zu. Erweiterungsmethoden werden nicht für die Erweiterung geschlossen, sondern sind eine Erweiterung. Sie schreiben den Kern Ihres Frameworks, der alles kann, was es sollte, und bieten mit Erweiterungsmethoden einige zusätzliche Funktionen, möglicherweise einige Standardhilfen, aber jeder andere kann seine eigenen Erweiterungen schreiben. Ich würde sagen, wenn Ihr Framework Erweiterungsmethoden akzeptiert , um es zu erweitern, dann ist es ein gutes Framework.
t3chb0t
6

Nachdem ich mir den besten Vergleich angesehen habe, den ich bisher gefunden habe, ist:

Es war eine Umfrage im März 2010.

Ein Punkt von Interesse für mich ist, dass Leute, die ein DI / IoC-Framework verwendet haben und es mochten / nicht mochten, StructureMap anscheinend die Nase vorn haben.

Auch aus der Umfrage geht hervor, dass Castle.Windsor und StructureMap am meisten bevorzugt werden.

Interessanterweise scheinen Unity und Spring.Net die beliebtesten Optionen zu sein, die im Allgemeinen nicht gemocht werden. (Ich habe Unity aus Faulheit (und Microsoft-Badge / Support) in Betracht gezogen, aber ich werde mir Castle Windsor und StructureMap jetzt genauer ansehen.)

Natürlich trifft dies wahrscheinlich (?) Nicht auf Unity 2.0 zu, das im Mai 2010 veröffentlicht wurde.

Hoffentlich kann jemand anderes einen Vergleich liefern, der auf direkten Erfahrungen basiert.

ocodo
quelle
2
Die Einheit ist ziemlich gut. Es deckt das meiste ab, was man braucht, obwohl sich einige Leute darüber beschweren, dass zirkuläre Abhängigkeiten nicht gelöst werden. Ich liebe es. Ich mache alles was ich brauche.
Dmitri Nesteruk
Viele Entwickler verwenden Castle.Windsor, ohne es zu wissen. Dies ist das Standard-Ioc für NHibernate . (Zumindest mit dem FluentNHibernate habe ich gestern downloded). Ich habe auch eine NHibernate-Implementierung gesehen, die LinFu nstead verwendet
k3b
5

Sehen Sie für einen Vergleich von Net-Ioc-Frameworks auf Google-Code, einschließlich Linfu und Spring.net, die nicht auf Ihrer Liste sind, während ich diesen Text schreibe.

Ich habe mit spring.net gearbeitet: Es hat viele Funktionen (aop, Bibliotheken, Doku, ...) und es gibt viel Erfahrung damit im Dotnet und in der Java-Welt. Die Funktionen sind modularisiert, sodass Sie nicht alle Funktionen nutzen müssen. Bei den Funktionen handelt es sich um Abstraktionen häufig auftretender Probleme wie Datenbasisabnahme und Protokollabstraktion. Es ist jedoch schwierig, die IoC-Konfiguration durchzuführen und zu debuggen.

Nach dem, was ich bisher gelesen habe: Wenn ich mich für ein kleines oder mittleres Projekt entscheiden müsste, würde ich ninject verwenden, da die ioc-Konfiguration in c # abgeschlossen und debuggbar ist. Aber ich habe noch nicht damit gearbeitet. für große modulare systeme würde ich wegen abstraktionsbibliotheken bei spring.net bleiben.

k3b
quelle