Comment se comparent les principaux frameworks C # DI / IoC? [fermé]


308

Au risque de pénétrer sur le territoire de la guerre sainte, quelles sont les forces et les faiblesses de ces cadres DI / IoC populaires, et pourrait-on facilement considérer comme le meilleur? ..:

  • Ninject
  • Unité
  • Castle.Windsor
  • Autofac
  • StructureMap

Existe-t-il d'autres cadres DI / IoC pour C # que je n'ai pas répertoriés ici?

Dans le cadre de mon cas d'utilisation, je crée une application WPF cliente et une infrastructure de services WCF / SQL, la facilité d'utilisation (en particulier en termes de syntaxe claire et concise), une documentation cohérente, un bon support communautaire et des performances sont tous des facteurs importants dans mon choix.

Mettre à jour:

Les ressources et les questions en double citées semblent être obsolètes, une personne connaissant tous ces cadres peut-elle se présenter et fournir de véritables informations?

Je me rends compte que la plupart des opinions sur ce sujet sont susceptibles d'être biaisées, mais j'espère que quelqu'un a pris le temps d'étudier tous ces cadres et d'avoir au moins une comparaison généralement objective.

Je suis tout à fait disposé à faire mes propres enquêtes si cela n'a pas été fait auparavant, mais j'ai supposé que c'était quelque chose qu'au moins quelques personnes avaient déjà fait.

Deuxième mise à jour:

Si vous avez de l'expérience avec plus d'un conteneur DI / IoC, veuillez classer et résumer les avantages et les inconvénients de ceux-ci, merci. Ce n'est pas un exercice pour découvrir tous les petits conteneurs obscurs que les gens ont faits, je cherche des comparaisons entre les frameworks populaires (et actifs).


1
Même question que [Ninject vs Unity for DI] ( stackoverflow.com/questions/1054801/ninject-vs-unity-for-di ), mais il peut être temps de faire un suivi.
Matthew Flaschen le

2
doublon possible de [Comparaison de Castle Windsor, Unity et StructureMap] ( stackoverflow.com/questions/2216684/… )
Mauricio Scheffer

@slomojo: doublon possible. stackoverflow.com/questions/4509458/ioc-comparisions-closed . Il y a aussi un lien qui montre la popularité des IoC dans la réponse. Jetez-y un œil.
dhinesh

@chibacity - Je l'ai utilisé sur ... 4 projets, les deux premiers étaient vraiment basiques, aucun problème, les deuxièmes, Unity nous a causé tellement de problèmes en ce qui concerne l'injection de constructeur, la maintenabilité, la lisibilité. Nous avons fini par arracher Unity des deux et l'avons remplacé par StructureMap, l'injection du constructeur était simple, la configuration était propre et maintenable. Dans mon temps personnel, j'ai joué avec AutoFac, mais je le trouve difficile, besoin de documentation pour mieux le comprendre. Le reste, je ne peux que commenter ce que j'ai lu.
Phill

Un problème que nous avions était avec SSRS, il échouait silencieusement et en parcourant le code, nous ne pouvions pas comprendre pourquoi il échouait, l'exception était ambiguë. Nous avons passé une semaine à écrire des solutions pour le faire fonctionner. Finalement, lorsque nous sommes passés à StructureMap, nous avons eu une autre tentative, et en quelques minutes en utilisant «ObjectFactory.WhatDoIHave ()», nous avons appris que l'IoC était en cours de construction avant le chargement des assemblys dans l'AppDomain, de sorte que les interfaces n'étaient jamais enregistrées avec le béton. les types.
Phill

Réponses:


225

Alors qu'une réponse complète à cette question occupe des centaines de pages de mon livre , voici un tableau de comparaison rapide sur lequel je travaille toujours:

Un tableau expliquant la différence entre plusieurs DIC


40
J'ai lu le MEAP de votre livre et je me suis demandé pourquoi vous en avez laissé Ninject?
Martin Owen

2
Une réponse partielle peut être trouvée ici: manning-sandbox.com/thread.jspa?threadID=38943
Mark Seemann

25
@Mark, merci pour cela, j'espère que votre réponse pourrait inclure Ninject (important, non seulement en raison du nouveau battage médiatique qui l'entoure, mais aussi en raison de son utilisation de nouvelles fonctionnalités de langage.)
ocodo

3
Ninject, bien que similaire à AutoFac, est à bien des égards, il est utilisé par l'équipe NUGET et le conteneur IOC téléchargé le plus populaire de loin. J'ai été déçu que ce ne soit pas dans l'injection de dépendance de Mark dans le livre .NET. S'il y a une 2e édition à l'apparence de l'industrie, j'espère qu'elle en fera partie. Soit je rencontre Unity, MEF (pas une vraie DI), Ninject ou StructurMap, je n'ai tout simplement pas encore décroché de contrat ou de concert à distance qui utilise spring.net ou autofac etc ...
Tom Stickel

2
Unity 3.5 prend déjà en charge l'enregistrement basé sur les conventions: nuget.org/packages/Unity/3.5.1404 . Supprimer un inconvénient ;-)
Vladimir Dorokhov

116

Je suis tombé sur une autre comparaison de performances (dernière mise à jour 10 avril 2014). Il compare les éléments suivants:

Voici un bref résumé de l'article:

Conclusion

Ninject est certainement le conteneur le plus lent.

MEF, LinFu et Spring.NET sont plus rapides que Ninject, mais toujours assez lents. AutoFac, Catel et Windsor viennent ensuite, suivis de StructureMap, Unity et LightCore. Un inconvénient de Spring.NET est qu'il ne peut être configuré qu'avec XML.

SimpleInjector, Hiro, Funq, Munq et Dynamo offrent les meilleures performances, ils sont extrêmement rapides. Essayez-les!

L'injecteur particulièrement simple semble être un bon choix. C'est très rapide, a une bonne documentation et prend également en charge des scénarios avancés comme l'interception et les décorateurs génériques.

Vous pouvez également essayer d'utiliser la bibliothèque du sélecteur de services communs et, espérons-le, essayer plusieurs options et voir ce qui vous convient le mieux.

Quelques informations sur la bibliothèque Common Service Selector du site:

La bibliothèque fournit une abstraction sur les conteneurs IoC et les localisateurs de services. L'utilisation de la bibliothèque permet à une application d'accéder indirectement aux capacités sans s'appuyer sur des références solides. L'espoir est qu'en utilisant cette bibliothèque, les applications et les frameworks tiers peuvent commencer à exploiter IoC / Service Location sans se lier à une implémentation spécifique.

Mettre à jour

13.09.2011: Funq et Munq ont été ajoutés à la liste des candidats. Les graphiques ont également été mis à jour et Spring.NET a été supprimé en raison de ses performances médiocres.

04.11.2011: "a ajouté Simple Injector , la performance est la meilleure de tous les concurrents".


(D'après le lien de comparaison) Mise à jour récente, intéressante pour voir les différences de vitesse (plus la matrice des fonctionnalités de base). Merci.
lko

Cette comparaison n'est pas si fiable car, pour autant que je sache, Ninject a des extensions pour la configuration d'interception et XML, alors que la comparaison ne le fait pas.
Daniel

15
il s'agit d'une comparaison très quantitative. Qu'en est-il des fonctionnalités non performantes telles que la taille du fichier ou le nombre de dépendances requises? De plus, des mesures subjectives telles que la qualité ou l'utilisabilité de la documentation seraient utiles. Mon point est qu'il y a des facteurs à considérer autres que la vitesse.
FistOfFury

1
Comme Jeremy Miller, l'auteur de StructureMap a dit dans le passé ... paraphraser - C'est sûr qu'il y a des conteneurs IOC plus rapides, mais ils manquent d'un ensemble complet de fonctionnalités.
Tom Stickel


49

Il suffit de lire ce superbe blog de comparaison de conteneurs DI .Net de Philip Mat.

Il fait des tests de comparaison de performances approfondis sur;

Il recommande Autofac car il est petit, rapide et facile à utiliser ... Je suis d'accord. Il semble que Unity et Ninject soient les plus lents dans ses tests.


5
Il y a une mise à jour de la publication .Net DI Container Speed ​​Redux : En fin de compte, il y a eu une mauvaise approche pour Unity en premier lieu. Avec les nouvelles mesures, Unity est beaucoup mieux.
Volker von Einem

33

Avertissement: Au début de 2015, il y a une grande comparaison des IoC Container dispose de Jimmy Bogard , voici un résumé:

Conteneurs comparés:

  • Autofac
  • Ninject
  • Injecteur simple
  • StructureMap
  • Unité
  • Windsor

Le scénario est le suivant: j'ai une interface, IMediator, dans laquelle je peux envoyer une seule demande / réponse ou une notification à plusieurs destinataires:

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

J'ai ensuite créé un ensemble de base de demandes / réponses / notifications:

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

Je souhaitais examiner quelques éléments concernant la prise en charge des conteneurs pour les génériques:

  • Configuration pour les génériques ouverts (enregistrement IRequestHandler <,> facilement)
  • Configuration pour plusieurs enregistrements de génériques ouverts (deux ou plusieurs INotificationHandlers)

Configuration de la variance générique (enregistrement des gestionnaires pour la base INotification / création de pipelines de demande) Mes gestionnaires sont assez simples, ils sortent simplement sur la 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();
  • Génériques ouverts: oui, implicitement
  • Génériques ouverts multiples: oui, implicitement
  • Contrevariance générique: oui, explicitement

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);
  • Génériques ouverts: oui, implicitement
  • Génériques ouverts multiples: oui, implicitement
  • Contrevariance générique: oui, avec des extensions construites par l'utilisateur

Injecteur simple

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);
  • Génériques ouverts: oui, explicitement
  • Génériques ouverts multiples: oui, explicitement
  • Contrevariance générique: oui, implicitement (avec la mise à jour 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<>));
    });
});
  • Génériques ouverts: oui, explicitement
  • Génériques ouverts multiples: oui, explicitement
  • Contrevariance générique: oui, implicitement

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;
}
  • Génériques ouverts: oui, implicitement
  • Génériques ouverts multiples: oui, avec une extension construite par l'utilisateur
  • Contrevariance générique: 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());
  • Génériques ouverts: oui, implicitement
  • Génériques ouverts multiples: oui, implicitement
  • Contrevariance générique: oui, avec une extension construite par l'utilisateur

Excellent! Btw, le résumé ci-dessus a manqué Windsor, mais il est disponible dans l'article original de Jimmy.
Louis

Wow, personne ne l'avait prévenu avant (: j'ai ajouté windsor, merci @Louis
stratovarius

21

En fait, il existe des tonnes de cadres IoC. Il semble que chaque programmeur essaie d'en écrire un à un moment donné de sa carrière. Peut-être pas pour le publier, mais pour apprendre le fonctionnement interne.

Personnellement, je préfère autofac car il est assez flexible et a une syntaxe qui me convient (même si je déteste vraiment que toutes les méthodes de registre soient des méthodes d'extension).

Quelques autres cadres:


Salut @abatishchev! :) ... l'idée originale était de s'assurer que les méthodes tierces et intégrées étaient sur le même pied; de nombreuses méthodes de «registre» doivent être expédiées séparément (par exemple RegisterControllers()pour MVC), donc j'ai pensé que la conception autour de ce cas en valait la peine. (Ceci a été conçu il y a 5+ ans.)
Nicholas Blumhardt

1
@NicholasBlumhardt: Salut! :) Désolé pour une réponse tardive, la notification s'est perdue parmi les autres. En fait, un tel souci de cohérence est logique pour moi. Comment pensez-vous maintenant, comment le concevriez-vous?
abatishchev

@abatishchev Je ne suis pas d'accord avec jgauffin. Les méthodes d'extension ne sont pas fermées pour l'extension, elles sont l'extension. Vous écrivez le cœur de votre framework qui peut faire tout ce qu'il faut et avec des méthodes d'extension, vous fournissez des fonctionnalités supplémentaires, peut-être des aides par défaut, mais n'importe qui d'autre est libre d'écrire leurs propres extensions. Je dirais que si votre framework accepte des méthodes d'extension pour l'étendre, c'est un bon framework.
t3chb0t

6

Eh bien, après avoir regardé la meilleure comparaison que j'ai trouvée jusqu'à présent, voici:

Il s'agissait d'un sondage réalisé en mars 2010.

Un point d'intérêt pour moi est que les personnes qui ont utilisé un framework DI / IoC et l'ont aimé / détesté, StructureMap semblent sortir en tête.

Toujours d'après le sondage, il semble que Castle.Windsor et StructureMap semblent être les plus favorisés.

Fait intéressant, Unity et Spring.Net semblent être les options les plus populaires qui sont le plus généralement détestées. (Je considérais Unity par paresse (et le badge / support Microsoft), mais je vais maintenant regarder de plus près Castle Windsor et StructureMap.)

Bien sûr, cela (?) Ne s'applique probablement pas à Unity 2.0 qui a été publié en mai 2010.

J'espère que quelqu'un d'autre pourra fournir une comparaison basée sur l'expérience directe.


2
L'unité est plutôt bonne. Il couvre la plupart de ce dont on a besoin, bien que certaines personnes se plaignent de ne pas résoudre les dépendances circulaires. J'aime cela. Je fais tout ce dont j'ai besoin.
Dmitri Nesteruk du

De nombreux développeurs utilisent Castle.Windsor sans même le savoir. C'est l'Ioc par défaut pour NHibernate . (Au moins avec le FluentNHibernate j'ai downlodé hier). J'ai également vu une implémentation NHibernate qui utilise LinFu nstead
k3b

5

Voir pour une comparaison des frameworks net-ioc sur google code y compris linfu et spring.net qui ne sont pas sur votre liste pendant que j'écris ce texte.

J'ai travaillé avec spring.net: il a de nombreuses fonctionnalités (aop, bibliothèques, docu, ...) et il y a beaucoup d'expérience avec lui dans le dotnet et le monde java. Les fonctionnalités sont modulaires afin que vous n'ayez pas à prendre toutes les fonctionnalités. Les fonctionnalités sont des abstractions de problèmes courants comme l'abstraction de la base de données, l'abstraction de la journalisation. cependant, il est difficile de faire et de déboguer la configuration IoC.

D'après ce que j'ai lu jusqu'à présent: si je devais choisir h pour un petit ou moyen projet, j'utiliserais ninject car la configuration ioc est terminée et débogable en c #. Mais je n'ai pas encore travaillé avec. pour les grands systèmes modulaires, je resterais avec spring.net à cause des bibliothèques d'abstraction.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.