web-dev-qa-db-fra.com

Comment se comparent les principaux frameworks C # DI / IoC?

Au risque d'entrer dans le territoire de la guerre sainte, quelles sont les forces et les faiblesses de ces populaires cadres DI/IoC, et pourrait-on facilement être considéré 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 construis une application client WPF et une infrastructure de services WCF/SQL, une facilité d'utilisation (en particulier en termes de syntaxe claire et concise), une documentation cohérente, une bonne assistance de la communauté et des performances sont tous des facteurs importants. dans mon choix.

Mise à jour:

Les ressources et les questions en double citées semblent être obsolètes. Est-ce qu'une personne connaissant tous ces cadres peut se faire connaître et fournir un aperçu réel?

Je me rends compte que la plupart des opinions sur ce sujet risquent 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 que 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 fabriqués, je cherche des comparaisons entre les frameworks populaires (et actifs).

295
ocodo

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

A table explaining difference between several DICs

220
Mark Seemann

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

Voici un résumé rapide du post:

Conclusion

Ninject est définitivement le conteneur le plus lent.

MEF, LinFu et Spring.NET sont plus rapides que Ninject, mais restent 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. Il est très rapide, possède une bonne documentation et prend également en charge des scénarios avancés tels que l’interception et les décorateurs génériques.

Vous pouvez également essayer d'utiliser Common Service Selector Library et, si tout va bien, 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 fonctionnalités sans recourir à des références matérielles. L'espoir est qu'en utilisant cette bibliothèque, les applications et les infrastructures tierces puissent commencer à exploiter IoC/Service Location sans se lier à une implémentation spécifique.

Mise à 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: "ajouta Simple Injector , la performance est le meilleur de tous les concurrents".

110
Pranav Shah

Il suffit de lire ce grand . Blog de comparaison de conteneurs .NET DI par Philip Mat.

Il effectue des tests de comparaison de performance approfondis;

Il recommande Autofac car il est petit, rapide et facile à utiliser ... Je suis d’accord. Il apparaît que nité et Ninject sont les plus lents dans ses tests.

48
brodie

Avertissement: Début 2015, il existe une excellente comparaison des fonctionnalités de IoC Container 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 points concernant le support des conteneurs pour génériques:

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

Configuration pour la variance générique (enregistrement des gestionnaires pour INotification de base/création de pipelines de demandes) Mes gestionnaires sont assez simples, ils sortent simplement vers 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
  • Plusieurs génériques ouverts: oui, implicitement
  • Contravariance 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
  • Plusieurs génériques ouverts: oui, implicitement
  • Contrevariance générique: oui, avec des extensions construites par l'utilisateur

Simple Injector

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
  • Plusieurs génériques ouverts: oui, explicitement
  • Contravariance 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
  • Plusieurs génériques ouverts: oui, explicitement
  • Contravariance 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
  • Plusieurs génériques ouverts: oui, avec une extension construite par l'utilisateur
  • Contravariance 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
  • Plusieurs génériques ouverts: oui, implicitement
  • Contravariance générique: oui, avec une extension construite par l'utilisateur
29
stratovarius

En fait, il y a des tonnes de frameworks IoC. Il semble que tous les programmeurs essaient d’en écrire un à un moment donné de leur carrière. Peut-être pas pour le publier, mais pour apprendre le fonctionnement interne.

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

Quelques autres cadres:

20
jgauffin

Après avoir regardé autour de moi, la meilleure comparaison que j'ai trouvée jusqu'à présent est la suivante:

C'était un sondage réalisé en mars 2010.

Un des points qui m’intéresse, c’est que les personnes qui ont utilisé un framework DI/IoC et l’ont aimé/n’ont pas aimé, StructureMap semble sortir du lot.

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

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

Bien sûr, cela ne s'applique probablement pas à Unity 2.0, publié en mai 2010.

Espérons que quelqu'un d'autre puisse fournir une comparaison basée sur l'expérience directe.

6
ocodo

Voir pour une comparaison de net-ioc-frameworks sur le code de Google incluant linfu et spring.net qui ne figurent 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 possède une grande expérience dans le domaine de la dotnet et du monde Java. Les fonctionnalités sont modulaires, vous n’avez donc pas besoin de toutes les fonctionnalités. Les fonctionnalités sont des abstractions de problèmes courants tels que l'absorption 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 un projet de taille petite ou moyenne, j'utiliserais ninject puisque la configuration d'ioc est terminée et peut être déboguée 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.

5
k3b